Skip to content

Support syntax-only SPDX expression parsing - #25

Open
abhinavgautam01 wants to merge 3 commits into
git-pkgs:mainfrom
abhinavgautam01:feat/24-syntax-only-parsing
Open

Support syntax-only SPDX expression parsing#25
abhinavgautam01 wants to merge 3 commits into
git-pkgs:mainfrom
abhinavgautam01:feat/24-syntax-only-parsing

Conversation

@abhinavgautam01

Copy link
Copy Markdown

Closes #24

Summary

Add ParseSyntax, a syntax-only SPDX expression parser that does not require bare license and exception identifiers to exist in the SPDX identifier list bundled by github/go-spdx.

This allows callers with a separately pinned identifier source—such as git-pkgs/licenses and its ScanCode corpus—to parse an expression before resolving its identifiers independently.

API

expression, err := spdx.ParseSyntax("Future-License-1.0 OR MIT")

Unlike ParseStrict, this succeeds when an unknown identifier is syntactically valid:

_, err := spdx.ParseStrict("Future-License-1.0 OR MIT")
// ErrInvalidLicenseID

Behavior

ParseSyntax:

  • Validates SPDX expression structure and identifier syntax
  • Supports AND, OR, WITH, parentheses, and +
  • Supports LicenseRef-* and DocumentRef-*:LicenseRef-*
  • Canonicalizes identifiers present in the bundled SPDX list
  • Preserves well-formed unknown license and exception identifiers as written
  • Rejects malformed identifiers and expressions
  • Enforces the existing expression-size and nesting-depth limits

ParseStrict retains its existing behavior and continues to require identifiers from the bundled SPDX list.

Testing

Added regression coverage for:

  • Unknown but well-formed license identifiers
  • Unknown but well-formed exception identifiers
  • Strict-mode rejection of those identifiers
  • AST equivalence between ParseSyntax and ParseStrict for known expressions
  • Operators, precedence, parentheses, WITH, +, and license references
  • Malformed expressions and invalid identifier characters
  • Maximum expression size and nesting depth

Validation

  • gofmt
  • git diff --check
  • go build ./...
  • go vet ./...
  • go test -count=1 ./...
  • go test -race -count=1 ./...
  • golangci-lint v2.12.2 — 0 issues

Follow-up

This unblocks git-pkgs/licenses#2, which can use ParseSyntax and resolve identifiers against its pinned ScanCode mapping.

@abhinavgautam01

Copy link
Copy Markdown
Author

@andrew I've prepared the follow-up fix for git-pkgs/licenses#2 and validated it locally against this branch. Since it depends on the new ParseSyntax API, I'll open the PR once you have time to review and merge this one.

@andrew andrew left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please address these before merging:

  • Validate LicenseRef and DocumentRef components with validIdentifier. ParseSyntax currently accepts malformed values such as LicenseRef-, LicenseRef-invalid/value, and DocumentRef-vendor; some are silently rewritten into different references.
  • Extract identifier resolution from parseAtom. The added nesting raises its cognitive complexity to 34, above the review threshold of 30.

@abhinavgautam01

Copy link
Copy Markdown
Author

Thanks for the review, I’ve addressed both points:

  • LicenseRef and DocumentRef components are now validated with validIdentifier. I added regression coverage for the malformed examples you listed, along with missing document and license-reference components.
  • License/exception resolution and reference parsing have been extracted from parseAtom, bringing it below the cognitive-complexity threshold.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new public API, ParseSyntax, to parse SPDX license expressions in a syntax-only mode that validates grammar and identifier shape without requiring license/exception identifiers to exist in the SPDX identifier list bundled with this module. This supports callers that validate identifiers against a separately pinned corpus while still enforcing expression structure and existing size/depth limits.

Changes:

  • Add ParseSyntax and plumb an allowUnknownIdentifiers mode through the parser so unknown-but-well-formed identifiers can be preserved.
  • Refactor parsing entrypoints to share a (*parser).parse() helper and add identifier/reference validation helpers.
  • Add a new test suite covering syntax-only parsing behavior, strict-mode rejection, malformed expressions, and limits.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
README.md Documents the new ParseSyntax API and when to use it vs ParseStrict.
parse.go Adds syntax-only parsing mode and identifier/reference validation helpers.
parse_syntax_test.go Adds regression tests for unknown identifiers, AST equivalence, malformed expressions, and limits.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread parse_syntax_test.go
Comment thread parse.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support syntax-only SPDX expression parsing

3 participants