SPDX license expression functionality, as defined in SPDX Specification Annex B.
This functionality is bespoke (it does not use the parser in Spdx-Java-Library).
SPDX license expression functionality, as defined in [SPDX Specification Annex B](https://spdx.github.io/spdx-spec/v3.0.2/annexes/spdx-license-expressions/). This functionality is bespoke (it does not use the parser in `Spdx-Java-Library`).
(canonicalise s)(canonicalise s opts)Canonicalises an SPDX expression, by running it through parse then
unparse. Returns nil if s is not a valid SPDX expression.
opts are as for parse
Canonicalises an SPDX expression, by running it through [[parse]] then [[unparse]]. Returns `nil` if `s` is not a valid SPDX expression. `opts` are as for [[parse]]
(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.
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 parse-tree)(extract-ids parse-tree
{:keys [include-or-later?] :or {include-or-later? false}})Extract all SPDX ids (as a set of Strings) from parse-tree. Results are
undefined for invalid parse trees.
The optional opts map has these keys:
:include-or-later? (boolean, default false) - controls whether the output
includes the 'or later' indicator (+) after license ids that have that
designation in the parse tree.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`, default `false`) - controls whether the output includes the 'or later' indicator (`+`) after license ids that have that designation in the parse tree.
(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 function may have a substantial performance cost.
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 function may have a substantial performance cost.
(parse s)(parse s
{:keys [canonicalise-deprecated-ids? collapse-redundant-clauses?
sort-licenses?]
:or {canonicalise-deprecated-ids? true
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. License ids, LicenseRefs, special forms, and any associated 'or
later' markers, exception ids, or AdditionRefs are represented as a map, and
sequences of these separated by operators are represented as vectors with the
operator represented by a keyword in the first element, and with maps in the
rest of the vector. Groups (vectors) may be arbitrarily nested e.g. when the
expression contains nested clauses.
The optional opts map has these keys:
:canonicalise-deprecated-ids? (boolean, default true) - controls
whether deprecated ids in the expression are canonicalised to their
non-deprecated equivalents (where possible) as part of the parsing process.
Note that not all deprecated identifiers have non-deprecated equivalents,
and those that don't will be left unchanged in the parse tree.:collapse-redundant-clauses? (boolean, default true) - controls
whether redundant clauses (e.g. "Apache-2.0 AND Apache-2.0") are
collapsed during parsing. Note: disabling sorting (:sort-licenses?) may
cause redundant clauses to remain in the parse tree.:sort-licenses? (boolean, default true) - 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 for Apache-2.0 OR MIT would be identical to the parse tree
for MIT OR Apache-2.0.Deprecated & removed opts:
:case-sensitive-operators? - changes to the case sensitivity rules in SPDX
v3.0.2 made this redundant:normalise-deprecated-ids? - superceded by :canonicalise-deprecated-ids?:normalise-gpl-ids? - superceded by :canonicalise-deprecated-ids?Notes:
aPAcHe-2.0 -> Apache-2.0(((((Apache-2.0)))))) -> Apache-2.0GPL-3.0-only+ -> GPL-3.0-or-laterExamples (assuming default options):
; Simple SPDX expression (single license identifier)
(parse "Apache-2.0")
{:license-id "Apache-2.0"}
; Identifier case correction, or-later? flag
(parse "apache-2.0+")
{:license-id "Apache-2.0" :or-later? true}
; GNU family identifier canonicalisation
(parse "GPL-2.0+")
{:license-id "GPL-2.0-or-later"}
; Deprecated identifier canonicalisation
(parse "StandardML-NJ")
{:license-id "SMLNJ"}
; License exceptions
(parse "GPL-2.0 WITH Classpath-exception-2.0")
{:license-id "GPL-2.0-only"
:license-exception-id "Classpath-exception-2.0"}
; Nesting (due to operator precedence), and sorting
(parse "MIT OR BSD-2-Clause AND Apache-2.0")
[:or
{:license-id "MIT"}
[:and
{:license-id "Apache-2.0"}
{:license-id "BSD-2-Clause"}]]
; LicenseRefs (custom license identifiers)
(parse "DocumentRef-foo:LicenseRef-bar")
{:document-ref "foo"
:license-ref "bar"}
; AdditionRefs (custom license exception identifiers, added in SPDX 3.0)
(parse "Apache-2.0 with DocumentRef-foo:AdditionRef-bar")
{:license-id "Apache-2.0"
:addition-document-ref "foo"
:addition-ref "bar"}
; Special forms (NONE and NOASSERTION)
(parse "NONE OR NOASSERTION")
[:or
{:special-form :no-assertion}
{:special-form :none}]
Attempt to parse `s` (a `String`) as an [SPDX license expression](https://spdx.github.io/spdx-spec/v3.0.2/annexes/spdx-license-expressions/),
returning a data structure representing the parse tree, or `nil` if it cannot
be parsed. License ids, LicenseRefs, special forms, and any associated 'or
later' markers, exception ids, or AdditionRefs are represented as a map, and
sequences of these separated by operators are represented as vectors with the
operator represented by a keyword in the first element, and with maps in the
rest of the vector. Groups (vectors) may be arbitrarily nested e.g. when the
expression contains nested clauses.
The optional `opts` map has these keys:
* `:canonicalise-deprecated-ids?` (`boolean`, default `true`) - controls
whether deprecated ids in the expression are canonicalised to their
non-deprecated equivalents (where possible) as part of the parsing process.
Note that not all deprecated identifiers have non-deprecated equivalents,
and those that don't will be left unchanged in the parse tree.
* `:collapse-redundant-clauses?` (`boolean`, default `true`) - controls
whether redundant clauses (e.g. `"Apache-2.0 AND Apache-2.0"`) are
collapsed during parsing. Note: disabling sorting (`:sort-licenses?`) may
cause redundant clauses to remain in the parse tree.
* `:sort-licenses?` (`boolean`, default `true`) - 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 for `Apache-2.0 OR MIT` would be identical to the parse tree
for `MIT OR Apache-2.0`.
Deprecated & removed `opts`:
* `:case-sensitive-operators?` - changes to the case sensitivity rules in SPDX
v3.0.2 made this redundant
* `:normalise-deprecated-ids?` - superceded by `:canonicalise-deprecated-ids?`
* `:normalise-gpl-ids?` - superceded by `:canonicalise-deprecated-ids?`
Notes:
* The parser always canonicalises SPDX identifiers
e.g. `aPAcHe-2.0` -> `Apache-2.0`
* The parser always removes redundant grouping
e.g. `(((((Apache-2.0))))))` -> `Apache-2.0`
* The parser always corrects nonsensical combinations of GNU family
license identifiers with the 'or later' marker
e.g. `GPL-3.0-only+` -> `GPL-3.0-or-later`
* The parser synthesises grouping when needed to make SPDX license
expressions' precedence rules explicit (see [the relevant section within
annex B of the SPDX specification](https://spdx.github.io/spdx-spec/v3.0.2/annexes/spdx-license-expressions/#order-of-precedence-and-parentheses)
for details).
Examples (assuming default options):
```clojure
; Simple SPDX expression (single license identifier)
(parse "Apache-2.0")
{:license-id "Apache-2.0"}
; Identifier case correction, or-later? flag
(parse "apache-2.0+")
{:license-id "Apache-2.0" :or-later? true}
; GNU family identifier canonicalisation
(parse "GPL-2.0+")
{:license-id "GPL-2.0-or-later"}
; Deprecated identifier canonicalisation
(parse "StandardML-NJ")
{:license-id "SMLNJ"}
; License exceptions
(parse "GPL-2.0 WITH Classpath-exception-2.0")
{:license-id "GPL-2.0-only"
:license-exception-id "Classpath-exception-2.0"}
; Nesting (due to operator precedence), and sorting
(parse "MIT OR BSD-2-Clause AND Apache-2.0")
[:or
{:license-id "MIT"}
[:and
{:license-id "Apache-2.0"}
{:license-id "BSD-2-Clause"}]]
; LicenseRefs (custom license identifiers)
(parse "DocumentRef-foo:LicenseRef-bar")
{:document-ref "foo"
:license-ref "bar"}
; AdditionRefs (custom license exception identifiers, added in SPDX 3.0)
(parse "Apache-2.0 with DocumentRef-foo:AdditionRef-bar")
{:license-id "Apache-2.0"
:addition-document-ref "foo"
:addition-ref "bar"}
; Special forms (NONE and NOASSERTION)
(parse "NONE OR NOASSERTION")
[:or
{:special-form :no-assertion}
{:special-form :none}]
```(parse-with-info s)(parse-with-info s
{:keys [canonicalise-deprecated-ids?
collapse-redundant-clauses? sort-licenses?]
:or {canonicalise-deprecated-ids? true
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
As for [[parse]], but returns an [instaparse parse error](https://github.com/Engelberg/instaparse#parse-errors) if parsing fails, instead of `nil`. `opts` are as for [[parse]]
(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.
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 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.
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? s)(valid? s opts)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
function first (doing so avoids double parsing).
The optional opts map has these keys:
Deprecated & removed opts:
:case-sensitive-operators? - changes to the case sensitivity rules in SPDX
v3.0.2 made this redundantIs `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 function first (doing so avoids double parsing). The optional `opts` map has these keys: * None, currently Deprecated & removed `opts`: * `:case-sensitive-operators?` - changes to the case sensitivity rules in SPDX v3.0.2 made this redundant
(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. Returns nil if parse-tree is
nil. 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,
LicenseRef, or special form 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 walkedDepth-first walk of `parse-tree` (i.e. obtained from [[parse]]), calling the
associated functions (or [`clojure.core/identity`](https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/identity)
when not provided) for each element in it. Returns `nil` if `parse-tree` is
`nil`. 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,
LicenseRef, or special form 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 walkedcljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |