Skip to content

Introduce simple CLI "check" - #3

Merged
bananaplain merged 12 commits into
mainfrom
feat/cli-check
Sep 29, 2026
Merged

bananaplain merged 12 commits into
mainfrom
feat/cli-check

Conversation

@bananaplain

@bananaplain bananaplain commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Adds a CLI that validates a .plain module, mirroring the checks codeplain --dry-run performs:

plain-parser check <file.plain> [--template-dir DIR] [--config-name NAME]

It parses the module and its requires chain, loads every linked resource, and walks each FRID of the top module. Output is <file>: OK on success, Error: … on stderr otherwise.

Exit codes: 0 valid, 1 invalid spec or missing file, 2 usage error, 130 on Ctrl-C.

--template-dir falls back to the template-dir key of config.yaml (or the file named by --config-name), looked up next to the spec and then in the working directory. Found in both, it is a usage error. Other config keys are ignored.

Not yet ported:
---> linked resources are still resolved against the working directory rather than the spec's directory.
---> Run check from the spec's directory until that lands (separate PR)

A skip would let a broken [project.scripts] entry pass CI. Also document
the two config rules the README left out: ambiguity is a usage error and
the config file is read even with --template-dir.

@zanjonke zanjonke 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.

Looks good overall. One minor request 🚀

Comment thread src/plain_parser/plain_file.py Outdated
Comment on lines 778 to 781

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

the function below implements what this function already has. i think it would be better if this one is used.

process_required_modules only parsed each ancestor for its exported
concepts and dropped the tree, so parse_module_chain had to run
plain_file_parser again on every ancestor to validate it and keep its
tree. Now process_required_modules runs the same post-parse validation
on each ancestor (validate_and_marshall_module, extracted from
plain_file_parser) and collects the marshalled trees; parse_module_chain
returns them. Every module is read and parsed once.

plain_file_parser alone now rejects an ancestor with an undefined
concept, a missing linked resource, or no implementation reqs. The
requires fixtures had ancestors without implementation reqs; they are
fixed.
return module_name, marshalled_plain_source, required_modules


def parse_module_chain(plain_file_name: str, template_dirs: list[str]) -> list[tuple[str, dict]]:

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The reason for the two functions that call the same _parse_module call, with different return signatures:

  • parse_module_chain returns every module's tree and the CLI (top + required).
    • CLI needs all the trees to load resources and plain_file_parser only returns the top module's tree
  • plain_file_parser keeps the 3-tuple return so the contract with codeplain holds until the upcoming refactor

The load steps in cli.py line 84, 85, remain and they're just walks over a list now - no module is actually re-read or re-parsed.

@bananaplain
bananaplain merged commit 5b3b20c into main Sep 29, 2026
1 check passed
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.

2 participants