spdx.expressions
SPDX license expression functionality. This functionality is bespoke (it does not use the parser in Spdx-Java-Library
).
compound?
(compound? s)
(compound? s opts)
Is s
(a String
) a ‘compound’ SPDX license expression (i.e. one that contains at least one AND or OR operator)? Returns nil
if s
not a valid SPDX expression.
The optional opts
map is as for parse
.
extract-ids
(extract-ids parse-tree)
(extract-ids parse-tree {:keys [include-or-later?], :or {include-or-later? false}})
Extract all SPDX ids (as a set of String
s) from parse-tree
. Results are undefined for invalid parse trees.
The optional opts
map has these keys:
:include-or-later?
(boolean
, defaultfalse
) - controls whether the output includes the ‘or later’ indicator (+
) after license ids that have that designation in the parse tree.
init!
(init!)
Initialises this namespace upon first call (and does nothing on subsequent calls), returning nil
. Consumers of this namespace are not required to call this fn, as initialisation will occur implicitly anyway; it is provided to allow explicit control of the cost of initialisation to callers who need it.
Note: this method may have a substantial performance cost.
normalise
(normalise s)
(normalise s opts)
parse
(parse s)
(parse s {:keys [normalise-deprecated-ids? case-sensitive-operators? collapse-redundant-clauses? sort-licenses?], :or {normalise-deprecated-ids? true, case-sensitive-operators? false, collapse-redundant-clauses? true, sort-licenses? true}, :as opts})
Attempt to parse s
(a String
) as an SPDX license expression, returning a data structure representing the parse tree, or nil
if it cannot be parsed. Licenses and associated license exceptions / ‘or later’ markers (if any) are represented as a map, groups of licenses separated by operators are represented as vectors, with the operator represented by a keyword in the first element in the vector and with license maps in the rest of the vector. Groups (vectors) may be nested e.g. when the expression contains nested clauses.
The optional opts
map has these keys:
:normalise-deprecated-ids?
(boolean
, defaulttrue
) - controls whether deprecated ids in the expression are normalised to their non-deprecated equivalents (where possible) as part of the parsing process. This applies to the GPL family of license ids, theAGPL-1.0
andStandardML-NJ
license ids and theNokia-Qt-exception-1.1
license exception id.:case-sensitive-operators?
(boolean
, defaultfalse
) - controls whether operators in expressions (AND
,OR
,WITH
) are case-sensitive (spec-compliant, but strict) or not (non-spec-compliant, lenient).:collapse-redundant-clauses?
(boolean
, defaulttrue
) - controls whether redundant clauses (e.g. “Apache-2.0 AND Apache-2.0”) are collapsed during parsing.:sort-licenses?
(boolean
, defaulttrue
) - controls whether licenses that appear at the same level in the parse tree are sorted alphabetically. This means that some parse trees will be identical for different (though logically identical) inputs, which can be useful in many cases. For example the parse tree forApache-2.0 OR MIT
would be identical to the parse tree forMIT OR Apache-2.0
.
Deprecated & no-longer-supported opts
:
:normalise-gpl-ids?
- superceded by:normalise-deprecated-ids?
Notes:
- The parser always normalises SPDX ids to their canonical case e.g.
aPAcHe-2.0
->Apache-2.0
- The parser always removes redundant grouping e.g.
(((((Apache-2.0))))))
->Apache-2.0
- The parser synthesises grouping when needed to make SPDX license expressions’ precedence rules explicit (see the relevant section within annex D of the SPDX specification for details).
- The default
opts
result in parsing that is more lenient than the SPDX specification and is therefore not strictly spec compliant. You can enable strictly spec compliant parsing by settingnormalise-deprecated-ids?
tofalse
andcase-sensitive-operators?
totrue
.
Examples (assuming default options):
(parse "Apache-2.0")
{:license-id "Apache-2.0"}
(parse "apache-2.0+")
{:license-id "Apache-2.0" :or-later? true} ; Note id case correction
(parse "GPL-2.0+")
{:license-id "GPL-2.0-or-later"} ; Note deprecated id normalisation
(parse "GPL-2.0 WITH Classpath-exception-2.0")
{:license-id "GPL-2.0-only"
:license-exception-id "Classpath-exception-2.0"}
(parse "(GPL-2.0+ with Classpath-exception-2.0) or CDDL-1.1") ; Note sorting
[:or
{:license-id "CDDL-1.1"}
{:license-id "GPL-2.0-or-later"
:license-exception-id "Classpath-exception-2.0"}]
(parse "DocumentRef-foo:LicenseRef-bar")
{:document-ref "foo"
:license-ref "bar"}
(parse "Apache-2.0 with DocumentRef-foo:AdditionRef-bar")
{:license-id "Apache-2.0"
:addition-document-ref "foo"
:addition-ref "bar"}
parse-with-info
(parse-with-info s)
(parse-with-info s {:keys [normalise-deprecated-ids? case-sensitive-operators? collapse-redundant-clauses? sort-licenses?], :or {normalise-deprecated-ids? true, case-sensitive-operators? false, collapse-redundant-clauses? true, sort-licenses? true}})
As for parse, but returns an instaparse parse error if parsing fails, instead of nil
.
opts
are as for parse
simple?
(simple? s)
(simple? s opts)
Is s
(a String
) a ‘simple’ SPDX license expression (i.e. one that contains no AND or OR operators, though it may contain a WITH operator)? Returns nil
if s
not a valid SPDX expression.
The optional opts
map is as for parse
.
unparse
(unparse parse-tree)
Turns a valid parse-tree
(i.e. obtained from parse) back into an SPDX expression (a String
), or nil
if parse-tree
is nil
. Results are undefined for invalid parse trees.
valid?
(valid? s)
(valid? s {:keys [case-sensitive-operators?], :or {case-sensitive-operators? false}})
Is s
(a String
) a valid SPDX license expression?
Note: if you intend to parse s
if it’s valid, it’s more efficient to call parse directly and check for a nil
result instead of calling this method first (doing so avoids double parsing).
The optional opts
map has these keys:
:case-sensitive-operators?
(boolean
, defaultfalse
) - controls whether operators in expressions (AND
,OR
,WITH
) are case-sensitive (spec-compliant, but strict) or not (non-spec-compliant, lenient).
walk
(walk {:keys [op-fn license-fn group-fn], :or {op-fn identity, license-fn identity, group-fn (fn [depth group] group)}, :as fns} parse-tree)
Depth-first walk of parse-tree
(i.e. obtained from parse), calling the associated functions (or clojure.core/identity
when not provided) for each element in it. Results are undefined for invalid parse trees.
Keys in the fns
map are:
:op-fn
- function of 1 argument (a keyword) to be called call when an operator (:and
,:or
) is visited:license-fn
- function of 1 argument (a map) to be called when a license map is visited:group-fn
- function of 2 arguments (an integer and a sequence) to be called when a group is visited. The first argument is the current nesting depth of the walk (starting at 0 for the outermost level), the second is the value of the group after its elements have been walked