Skip to content

Speculator Linter

speculator-lint brings the rigor of code quality tools to the world of technical authoring. It analyzes the Speculator AST to catch conceptual errors that standard spellcheckers and Markdown linters miss.

  • workspace/no-redefinition (Error): Prevents lower-level specs from redefining terms already defined in higher-level specs.
  • workspace/no-reverse-dependency (Error): Ensures higher-level specs do not depend on lower-level specs, maintaining a clear hierarchy.
  • workspace/valid-dependencies (Error): Ensures that all dependencies listed in a document’s configuration exist within the workspace.
  • document/no-duplicate-definition (Error): A single document must not define the same term or alias multiple times.
  • document/require-cop-concept (Error): Enforces that all normative statements (MUST, SHOULD, etc.) that wrapped within <spec-statement/> elements have a CoP Concept assigned via explicit or inherited data-cop-concept attribute. Informative statements are ignored.
  • reference/no-ambiguous-reference (Warning): Flags references that resolve to multiple definitions. Use data-link-for to disambiguate.
  • reference/no-id-reference (Warning): Discourages hardcoded ID-based references (e.g., href="#my-id"). Use the semantic Context Pattern instead.
  • reference/no-unresolved-reference (Error/Warning): Ensures all semantic references are successfully resolved. Workspace references are errors; external references and citations are warnings.
  • vocab/validate-spec-terms (Warning): Validates that spec: prefixed IRIs reference valid terms from the W3C Spec Terms vocabulary. Reports unknown terms like spec:InvalidTerm.
Terminal window
# Lint your specification workspace
speculator-lint workspace.json

Speculator Lint supports configuration inheritance via the extends property.

{
"extends": ["recommended"],
"rules": {
"reference/no-id-reference": "error"
}
}
  • "extends": ["recommended"]: Enables all built-in rules with their standard severities. This is the baseline for most projects.
  • Rule Overrides: You can override specific rules from the preset by defining them in the rules object. Setting a rule to "off" will disable it entirely.

The recommended preset includes the following rules:

RuleSeverity
workspace/no-redefinitionerror
workspace/no-reverse-dependencyerror
workspace/valid-dependencieserror
document/no-duplicate-definitionerror
reference/no-ambiguous-referencewarning
reference/no-id-referencewarning
reference/no-unresolved-referenceerror
vocab/validate-spec-termswarning
document/require-cop-concepterror

For projects with multiple isolated specification groups (e.g., separate “core” and “addons” projects), you can use a speculator.workspace.json file as a named map. This ensures each group is built as its own isolated AST, preventing term or ID leakage between groups.

{
"coreSpecs": [{ "entry": "spec/core.md" }, { "entry": "spec/api.html" }],
"addonSpecs": [
{ "entry": "addons/ui/index.md" },
{ "entry": "addons/storage/index.md" }
]
}

Usage with workspace config:

Terminal window
speculator-lint speculator.workspace.json

To ensure your specifications remain valid before every commit, you can integrate speculator-lint with husky and lint-staged.

Because Speculator uses a cross-document resolution engine, the linter always checks the entire workspace even if only a single file is being committed. This ensures that a change in one file doesn’t break references in another.

{
"lint-staged": {
"spec/**/*.md": ["speculator-lint speculator.workspace.json"]
}
}

When you attempt to commit a Markdown file, lint-staged will trigger the linter. The linter will build the full workspace context, perform high-level validation, and block the commit if any errors (like redefinitions or broken references) are found.

You can create custom lint rules by implementing the LintRule interface, allowing you to enforce project-specific style guides or technical constraints across your entire spec suite.