@descent-vtt/spec-graph 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/CHANGELOG.md +410 -0
  2. package/README.md +102 -17
  3. package/dist/cli.d.ts +2 -2
  4. package/dist/cli.js +38 -19
  5. package/dist/cli.js.map +1 -1
  6. package/dist/directives.d.ts +9 -2
  7. package/dist/directives.js +15 -4
  8. package/dist/directives.js.map +1 -1
  9. package/dist/extract.d.ts +1 -1
  10. package/dist/extract.js +50 -16
  11. package/dist/extract.js.map +1 -1
  12. package/dist/glob.d.ts +44 -44
  13. package/dist/glob.js +152 -116
  14. package/dist/glob.js.map +1 -1
  15. package/dist/index.d.ts +3 -3
  16. package/dist/index.js +4 -2
  17. package/dist/index.js.map +1 -1
  18. package/dist/lifecycle.js +10 -2
  19. package/dist/lifecycle.js.map +1 -1
  20. package/dist/markdown.d.ts +53 -161
  21. package/dist/markdown.js +42 -864
  22. package/dist/markdown.js.map +1 -1
  23. package/dist/report.d.ts +23 -0
  24. package/dist/report.js +80 -0
  25. package/dist/report.js.map +1 -1
  26. package/dist/rules.js +48 -14
  27. package/dist/rules.js.map +1 -1
  28. package/dist/sections.d.ts +1 -1
  29. package/dist/sections.js +7 -3
  30. package/dist/sections.js.map +1 -1
  31. package/dist/select.d.ts +2 -2
  32. package/dist/select.js +3 -3
  33. package/dist/select.js.map +1 -1
  34. package/dist/source.d.ts +6 -19
  35. package/dist/source.js +4 -70
  36. package/dist/source.js.map +1 -1
  37. package/dist/types.d.ts +23 -3
  38. package/dist/types.js +1 -1
  39. package/dist/types.js.map +1 -1
  40. package/dist/vendor/spec-core/markdown/frontmatter.d.ts +103 -0
  41. package/dist/vendor/spec-core/markdown/frontmatter.js +459 -0
  42. package/dist/vendor/spec-core/markdown/frontmatter.js.map +1 -0
  43. package/dist/vendor/spec-core/markdown/headings.d.ts +45 -0
  44. package/dist/vendor/spec-core/markdown/headings.js +199 -0
  45. package/dist/vendor/spec-core/markdown/headings.js.map +1 -0
  46. package/dist/vendor/spec-core/markdown/index.d.ts +5 -0
  47. package/dist/vendor/spec-core/markdown/index.js +4 -0
  48. package/dist/vendor/spec-core/markdown/index.js.map +1 -0
  49. package/dist/vendor/spec-core/markdown/layout.d.ts +39 -0
  50. package/dist/vendor/spec-core/markdown/layout.js +28 -0
  51. package/dist/vendor/spec-core/markdown/layout.js.map +1 -0
  52. package/dist/vendor/spec-core/markdown/links.d.ts +22 -0
  53. package/dist/vendor/spec-core/markdown/links.js +364 -0
  54. package/dist/vendor/spec-core/markdown/links.js.map +1 -0
  55. package/dist/vendor/spec-core/markdown/lists.d.ts +22 -0
  56. package/dist/vendor/spec-core/markdown/lists.js +127 -0
  57. package/dist/vendor/spec-core/markdown/lists.js.map +1 -0
  58. package/dist/vendor/spec-core/markdown/scan.d.ts +36 -0
  59. package/dist/vendor/spec-core/markdown/scan.js +439 -0
  60. package/dist/vendor/spec-core/markdown/scan.js.map +1 -0
  61. package/dist/vendor/spec-core/markdown/syntax.d.ts +75 -0
  62. package/dist/vendor/spec-core/markdown/syntax.js +181 -0
  63. package/dist/vendor/spec-core/markdown/syntax.js.map +1 -0
  64. package/dist/vendor/spec-core/markdown/tables.d.ts +18 -0
  65. package/dist/vendor/spec-core/markdown/tables.js +86 -0
  66. package/dist/vendor/spec-core/markdown/tables.js.map +1 -0
  67. package/dist/vendor/spec-core/markdown/types.d.ts +287 -0
  68. package/dist/vendor/spec-core/markdown/types.js +9 -0
  69. package/dist/vendor/spec-core/markdown/types.js.map +1 -0
  70. package/dist/vendor/spec-core/path/index.d.ts +1 -0
  71. package/dist/vendor/spec-core/path/index.js +2 -0
  72. package/dist/vendor/spec-core/path/index.js.map +1 -0
  73. package/dist/vendor/spec-core/path/posix.d.ts +83 -0
  74. package/dist/vendor/spec-core/path/posix.js +150 -0
  75. package/dist/vendor/spec-core/path/posix.js.map +1 -0
  76. package/dist/vendor/spec-core/pattern/automaton.d.ts +129 -0
  77. package/dist/vendor/spec-core/pattern/automaton.js +340 -0
  78. package/dist/vendor/spec-core/pattern/automaton.js.map +1 -0
  79. package/dist/vendor/spec-core/pattern/charset.d.ts +58 -0
  80. package/dist/vendor/spec-core/pattern/charset.js +116 -0
  81. package/dist/vendor/spec-core/pattern/charset.js.map +1 -0
  82. package/dist/vendor/spec-core/pattern/glob.d.ts +121 -0
  83. package/dist/vendor/spec-core/pattern/glob.js +481 -0
  84. package/dist/vendor/spec-core/pattern/glob.js.map +1 -0
  85. package/dist/vendor/spec-core/pattern/index.d.ts +6 -0
  86. package/dist/vendor/spec-core/pattern/index.js +4 -0
  87. package/dist/vendor/spec-core/pattern/index.js.map +1 -0
  88. package/dist/{regex.d.ts → vendor/spec-core/pattern/regex.d.ts} +20 -29
  89. package/dist/{regex.js → vendor/spec-core/pattern/regex.js} +40 -49
  90. package/dist/vendor/spec-core/pattern/regex.js.map +1 -0
  91. package/dist/vendor/spec-core/text/index.d.ts +2 -0
  92. package/dist/vendor/spec-core/text/index.js +2 -0
  93. package/dist/vendor/spec-core/text/index.js.map +1 -0
  94. package/dist/vendor/spec-core/text/lines.d.ts +72 -0
  95. package/dist/vendor/spec-core/text/lines.js +156 -0
  96. package/dist/vendor/spec-core/text/lines.js.map +1 -0
  97. package/dist/yaml.d.ts +44 -12
  98. package/dist/yaml.js +115 -206
  99. package/dist/yaml.js.map +1 -1
  100. package/package.json +3 -2
  101. package/src/vendor/spec-core/LICENSE +21 -0
  102. package/src/vendor/spec-core/README.md +8 -0
  103. package/dist/regex.js.map +0 -1
package/dist/index.d.ts CHANGED
@@ -32,14 +32,14 @@ export type { AnalyseOptions, AnalyseSourcesOptions, AnalysisResult, Source } fr
32
32
  export { buildGraph, LOAD_BEARING_EDGES, OBLIGATION_EDGES } from './graph.js';
33
33
  export type { SpecGraph } from './graph.js';
34
34
  export { attributesOf, execute, matches, parseQuery, pattern, query, renderMatch, QueryError, DEFAULT_MATCH_LIMIT, SELECTOR_KEYS, } from './select.js';
35
- export { compilePattern, PatternError } from './regex.js';
36
- export type { Matcher, PatternOptions } from './regex.js';
35
+ export { compileRegex as compilePattern, RegexError as PatternError } from './vendor/spec-core/pattern/index.js';
36
+ export type { RegexMatcher as Matcher, RegexOptions as PatternOptions } from './vendor/spec-core/pattern/index.js';
37
37
  export type { ExecuteOptions, Match, NodeMatcher, Operator, Predicate, QuerySpec, StepSpec, } from './select.js';
38
38
  export { resolveStrict, runRules, sortDiagnostics, DEFAULT_SEVERITIES, RULE_DECISIONS, RULE_DESCRIPTIONS, RULE_IDS, RULE_QUERIES, } from './rules.js';
39
39
  export type { RuleOptions } from './rules.js';
40
40
  export { compileProjectRules, renderTemplate } from './project-rules.js';
41
41
  export type { CompiledProjectRules, ProjectRule } from './project-rules.js';
42
- export { createPainter, formatGraph, formatJson, formatMarkdown, formatReport, formatSarif, shouldUseAscii, shouldUseColor, } from './report.js';
42
+ export { createPainter, formatGitlab, formatGraph, formatJson, formatMarkdown, formatReport, formatSarif, shouldUseAscii, shouldUseColor, } from './report.js';
43
43
  export type { ColorEnvironment, GraphExportOptions, GraphFormat, Painter, ReporterOptions } from './report.js';
44
44
  export { extractDocument, extractSpecifications, classifyReference, inheritableFrontMatter, sectionPathAt, } from './extract.js';
45
45
  export { findSpecificationRegions, readRegionStatus, regionAt } from './sections.js';
package/dist/index.js CHANGED
@@ -27,10 +27,12 @@ export { main, parseArgs, HELP, UsageError, EXIT_OK, EXIT_FAILED, EXIT_ERROR } f
27
27
  export { analyse, analyseSources, createFamilyFilter, createHistoryMatcher, withDiagnostics, DEFAULT_CONCURRENCY, DEFAULT_PATTERNS, } from './runner.js';
28
28
  export { buildGraph, LOAD_BEARING_EDGES, OBLIGATION_EDGES } from './graph.js';
29
29
  export { attributesOf, execute, matches, parseQuery, pattern, query, renderMatch, QueryError, DEFAULT_MATCH_LIMIT, SELECTOR_KEYS, } from './select.js';
30
- export { compilePattern, PatternError } from './regex.js';
30
+ // The matcher behind `~=` lives in spec-core now (ADR-0017), and keeps the
31
+ // names it was published under here.
32
+ export { compileRegex as compilePattern, RegexError as PatternError } from './vendor/spec-core/pattern/index.js';
31
33
  export { resolveStrict, runRules, sortDiagnostics, DEFAULT_SEVERITIES, RULE_DECISIONS, RULE_DESCRIPTIONS, RULE_IDS, RULE_QUERIES, } from './rules.js';
32
34
  export { compileProjectRules, renderTemplate } from './project-rules.js';
33
- export { createPainter, formatGraph, formatJson, formatMarkdown, formatReport, formatSarif, shouldUseAscii, shouldUseColor, } from './report.js';
35
+ export { createPainter, formatGitlab, formatGraph, formatJson, formatMarkdown, formatReport, formatSarif, shouldUseAscii, shouldUseColor, } from './report.js';
34
36
  export { extractDocument, extractSpecifications, classifyReference, inheritableFrontMatter, sectionPathAt, } from './extract.js';
35
37
  export { findSpecificationRegions, readRegionStatus, regionAt } from './sections.js';
36
38
  export { resolveCorpus, documentOf } from './resolve.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Programmatic API.\n *\n * The CLI is a shell over `analyse`; anything the CLI can do, a build script, a\n * custom reporter or an editor extension can do too.\n *\n * ```ts\n * import { analyse, formatReport } from '@descent-vtt/spec-graph';\n *\n * const result = await analyse({ root: process.cwd(), patterns: ['docs/**\\/*.md'] });\n * if (!result.ok) console.error(formatReport(result, { color: true }));\n * ```\n *\n * For a corpus that is already in memory - a monorepo tool, a language server,\n * a test - skip the filesystem entirely:\n *\n * ```ts\n * import { analyseSources, query } from '@descent-vtt/spec-graph';\n *\n * const { graph } = analyseSources([{ path: 'adr/0001.md', text: '...' }]);\n * const ghosts = query(graph, 'item[openness=open] -delegates-to-> document[phase=retired]');\n * ```\n */\n\nexport {\n applyBaseline,\n formatBaseline,\n fingerprintOf,\n parseBaseline,\n BASELINE_VERSION,\n EMPTY_BASELINE,\n} from './baseline.js';\nexport type { Baseline, BaselineEntry, BaselineOutcome, ParsedBaseline, StaleEntry } from './baseline.js';\n\nexport { discoverConfig, loadConfig, parseConfig, CONFIG_FILES, CONFIG_PACKAGE_KEY } from './config.js';\nexport type { DiscoveredConfig, DiscoveryIO, LoadedConfig, SpecGraphConfig } from './config.js';\n\nexport { main, parseArgs, HELP, UsageError, EXIT_OK, EXIT_FAILED, EXIT_ERROR } from './cli.js';\nexport type { CliIO, CliOptions, Command } from './cli.js';\n\nexport {\n analyse,\n analyseSources,\n createFamilyFilter,\n createHistoryMatcher,\n withDiagnostics,\n DEFAULT_CONCURRENCY,\n DEFAULT_PATTERNS,\n} from './runner.js';\nexport type { AnalyseOptions, AnalyseSourcesOptions, AnalysisResult, Source } from './runner.js';\n\nexport { buildGraph, LOAD_BEARING_EDGES, OBLIGATION_EDGES } from './graph.js';\nexport type { SpecGraph } from './graph.js';\n\nexport {\n attributesOf,\n execute,\n matches,\n parseQuery,\n pattern,\n query,\n renderMatch,\n QueryError,\n DEFAULT_MATCH_LIMIT,\n SELECTOR_KEYS,\n} from './select.js';\n\nexport { compilePattern, PatternError } from './regex.js';\nexport type { Matcher, PatternOptions } from './regex.js';\nexport type {\n ExecuteOptions,\n Match,\n NodeMatcher,\n Operator,\n Predicate,\n QuerySpec,\n StepSpec,\n} from './select.js';\n\nexport {\n resolveStrict,\n runRules,\n sortDiagnostics,\n DEFAULT_SEVERITIES,\n RULE_DECISIONS,\n RULE_DESCRIPTIONS,\n RULE_IDS,\n RULE_QUERIES,\n} from './rules.js';\nexport type { RuleOptions } from './rules.js';\n\nexport { compileProjectRules, renderTemplate } from './project-rules.js';\nexport type { CompiledProjectRules, ProjectRule } from './project-rules.js';\n\nexport {\n createPainter,\n formatGraph,\n formatJson,\n formatMarkdown,\n formatReport,\n formatSarif,\n shouldUseAscii,\n shouldUseColor,\n} from './report.js';\nexport type { ColorEnvironment, GraphExportOptions, GraphFormat, Painter, ReporterOptions } from './report.js';\n\nexport {\n extractDocument,\n extractSpecifications,\n classifyReference,\n inheritableFrontMatter,\n sectionPathAt,\n} from './extract.js';\nexport { findSpecificationRegions, readRegionStatus, regionAt } from './sections.js';\nexport type { RegionStatus, SpecificationRegion } from './sections.js';\nexport type { Classification, ExtractedDocument, ExtractInput, ReferenceCandidate } from './extract.js';\n\nexport { resolveCorpus, documentOf } from './resolve.js';\nexport type { ResolvedCorpus, ResolveOptions } from './resolve.js';\n\nexport { scanMarkdown, slugify } from './markdown.js';\nexport type {\n FrontMatter,\n Heading,\n HtmlComment,\n Link,\n LinkForm,\n ListItem,\n Range,\n ScannedDocument,\n ScannedLine,\n} from './markdown.js';\n\nexport { parseDirectives, attr, attrList, bindItemDirectives, directiveFor } from './directives.js';\nexport type { Attribute, Directive, DirectiveName } from './directives.js';\n\nexport { parseFrontMatter, toRecord, valuesOf } from './yaml.js';\nexport type { YamlEntry } from './yaml.js';\n\nexport {\n isRetired,\n isStatusHeading,\n normaliseStatus,\n phaseFromPath,\n phaseOf,\n receptivityOf,\n supersessionTargetsIn,\n STATUS_KEYS,\n} from './lifecycle.js';\n\nexport { resolveItemState, KNOWN_STATE_WORDS } from './state.js';\nexport type { ResolvedState, StateInput } from './state.js';\n\nexport {\n familyFromPath,\n identify,\n isDocumentTarget,\n isExternal,\n looksLikePath,\n normaliseRef,\n parseBareRef,\n parsePrefixedRef,\n splitAnchor,\n ID_KEYS,\n} from './identity.js';\nexport type { DocumentIdentity, IdentityInput } from './identity.js';\n\nexport {\n compileGlob,\n createGlobMatcher,\n createReferenceFilter,\n globBase,\n globToRegExp,\n isGlob,\n walkFiles,\n DEFAULT_IGNORED_DIRECTORIES,\n MAX_FILE_SIZE,\n} from './glob.js';\nexport type { GlobMatcher, GlobOptions, WalkedFile, WalkOptions } from './glob.js';\n\nexport { compareRefs, createLineIndex, formatRef, refOf, spanOf } from './source.js';\nexport type { LineIndex } from './source.js';\n\nexport {\n basenamePosix,\n dirnamePosix,\n extnamePosix,\n isAbsolutePath,\n joinPosix,\n normalisePosix,\n resolveFrom,\n toPosix,\n} from './paths.js';\n\nexport { isProjectRule, DISPOSITIONS, EDGE_KINDS, EDGE_TRAITS, OPENNESS_OF, PROJECT_RULE_PREFIX } from './types.js';\nexport type {\n AnalysisSummary,\n AnyRuleId,\n DanglingReason,\n DanglingRef,\n Diagnostic,\n Disposition,\n DocumentNode,\n Edge,\n EdgeKind,\n EdgeOrigin,\n EdgeTraits,\n ItemNode,\n MisreadKey,\n NodeKind,\n Openness,\n ParseProblem,\n Phase,\n Position,\n Receptivity,\n ProjectRuleId,\n RelatedLocation,\n RuleId,\n Severity,\n SourceRef,\n Span,\n SpecNode,\n StateSignal,\n SuppressedRef,\n} from './types.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Programmatic API.\n *\n * The CLI is a shell over `analyse`; anything the CLI can do, a build script, a\n * custom reporter or an editor extension can do too.\n *\n * ```ts\n * import { analyse, formatReport } from '@descent-vtt/spec-graph';\n *\n * const result = await analyse({ root: process.cwd(), patterns: ['docs/**\\/*.md'] });\n * if (!result.ok) console.error(formatReport(result, { color: true }));\n * ```\n *\n * For a corpus that is already in memory - a monorepo tool, a language server,\n * a test - skip the filesystem entirely:\n *\n * ```ts\n * import { analyseSources, query } from '@descent-vtt/spec-graph';\n *\n * const { graph } = analyseSources([{ path: 'adr/0001.md', text: '...' }]);\n * const ghosts = query(graph, 'item[openness=open] -delegates-to-> document[phase=retired]');\n * ```\n */\n\nexport {\n applyBaseline,\n formatBaseline,\n fingerprintOf,\n parseBaseline,\n BASELINE_VERSION,\n EMPTY_BASELINE,\n} from './baseline.js';\nexport type { Baseline, BaselineEntry, BaselineOutcome, ParsedBaseline, StaleEntry } from './baseline.js';\n\nexport { discoverConfig, loadConfig, parseConfig, CONFIG_FILES, CONFIG_PACKAGE_KEY } from './config.js';\nexport type { DiscoveredConfig, DiscoveryIO, LoadedConfig, SpecGraphConfig } from './config.js';\n\nexport { main, parseArgs, HELP, UsageError, EXIT_OK, EXIT_FAILED, EXIT_ERROR } from './cli.js';\nexport type { CliIO, CliOptions, Command } from './cli.js';\n\nexport {\n analyse,\n analyseSources,\n createFamilyFilter,\n createHistoryMatcher,\n withDiagnostics,\n DEFAULT_CONCURRENCY,\n DEFAULT_PATTERNS,\n} from './runner.js';\nexport type { AnalyseOptions, AnalyseSourcesOptions, AnalysisResult, Source } from './runner.js';\n\nexport { buildGraph, LOAD_BEARING_EDGES, OBLIGATION_EDGES } from './graph.js';\nexport type { SpecGraph } from './graph.js';\n\nexport {\n attributesOf,\n execute,\n matches,\n parseQuery,\n pattern,\n query,\n renderMatch,\n QueryError,\n DEFAULT_MATCH_LIMIT,\n SELECTOR_KEYS,\n} from './select.js';\n\n// The matcher behind `~=` lives in spec-core now (ADR-0017), and keeps the\n// names it was published under here.\nexport { compileRegex as compilePattern, RegexError as PatternError } from './vendor/spec-core/pattern/index.js';\nexport type { RegexMatcher as Matcher, RegexOptions as PatternOptions } from './vendor/spec-core/pattern/index.js';\nexport type {\n ExecuteOptions,\n Match,\n NodeMatcher,\n Operator,\n Predicate,\n QuerySpec,\n StepSpec,\n} from './select.js';\n\nexport {\n resolveStrict,\n runRules,\n sortDiagnostics,\n DEFAULT_SEVERITIES,\n RULE_DECISIONS,\n RULE_DESCRIPTIONS,\n RULE_IDS,\n RULE_QUERIES,\n} from './rules.js';\nexport type { RuleOptions } from './rules.js';\n\nexport { compileProjectRules, renderTemplate } from './project-rules.js';\nexport type { CompiledProjectRules, ProjectRule } from './project-rules.js';\n\nexport {\n createPainter,\n formatGitlab,\n formatGraph,\n formatJson,\n formatMarkdown,\n formatReport,\n formatSarif,\n shouldUseAscii,\n shouldUseColor,\n} from './report.js';\nexport type { ColorEnvironment, GraphExportOptions, GraphFormat, Painter, ReporterOptions } from './report.js';\n\nexport {\n extractDocument,\n extractSpecifications,\n classifyReference,\n inheritableFrontMatter,\n sectionPathAt,\n} from './extract.js';\nexport { findSpecificationRegions, readRegionStatus, regionAt } from './sections.js';\nexport type { RegionStatus, SpecificationRegion } from './sections.js';\nexport type { Classification, ExtractedDocument, ExtractInput, ReferenceCandidate } from './extract.js';\n\nexport { resolveCorpus, documentOf } from './resolve.js';\nexport type { ResolvedCorpus, ResolveOptions } from './resolve.js';\n\nexport { scanMarkdown, slugify } from './markdown.js';\nexport type {\n FrontMatter,\n Heading,\n HtmlComment,\n Link,\n LinkForm,\n ListItem,\n Range,\n ScannedDocument,\n ScannedLine,\n} from './markdown.js';\n\nexport { parseDirectives, attr, attrList, bindItemDirectives, directiveFor } from './directives.js';\nexport type { Attribute, Directive, DirectiveName } from './directives.js';\n\nexport { parseFrontMatter, toRecord, valuesOf } from './yaml.js';\nexport type { YamlEntry } from './yaml.js';\n\nexport {\n isRetired,\n isStatusHeading,\n normaliseStatus,\n phaseFromPath,\n phaseOf,\n receptivityOf,\n supersessionTargetsIn,\n STATUS_KEYS,\n} from './lifecycle.js';\n\nexport { resolveItemState, KNOWN_STATE_WORDS } from './state.js';\nexport type { ResolvedState, StateInput } from './state.js';\n\nexport {\n familyFromPath,\n identify,\n isDocumentTarget,\n isExternal,\n looksLikePath,\n normaliseRef,\n parseBareRef,\n parsePrefixedRef,\n splitAnchor,\n ID_KEYS,\n} from './identity.js';\nexport type { DocumentIdentity, IdentityInput } from './identity.js';\n\nexport {\n compileGlob,\n createGlobMatcher,\n createReferenceFilter,\n globBase,\n globToRegExp,\n isGlob,\n walkFiles,\n DEFAULT_IGNORED_DIRECTORIES,\n MAX_FILE_SIZE,\n} from './glob.js';\nexport type { GlobMatcher, GlobOptions, WalkedFile, WalkOptions } from './glob.js';\n\nexport { compareRefs, createLineIndex, formatRef, refOf, spanOf } from './source.js';\nexport type { LineIndex } from './source.js';\n\nexport {\n basenamePosix,\n dirnamePosix,\n extnamePosix,\n isAbsolutePath,\n joinPosix,\n normalisePosix,\n resolveFrom,\n toPosix,\n} from './paths.js';\n\nexport { isProjectRule, DISPOSITIONS, EDGE_KINDS, EDGE_TRAITS, OPENNESS_OF, PROJECT_RULE_PREFIX } from './types.js';\nexport type {\n AnalysisSummary,\n AnyRuleId,\n DanglingReason,\n DanglingRef,\n Diagnostic,\n Disposition,\n DocumentNode,\n Edge,\n EdgeKind,\n EdgeOrigin,\n EdgeTraits,\n ItemNode,\n MisreadKey,\n NodeKind,\n Openness,\n ParseProblem,\n Phase,\n Position,\n Receptivity,\n ProjectRuleId,\n RelatedLocation,\n RuleId,\n Severity,\n SourceRef,\n Span,\n SpecNode,\n StateSignal,\n SuppressedRef,\n} from './types.js';\n"]}
package/dist/lifecycle.js CHANGED
@@ -34,8 +34,6 @@ const VOCABULARY = [
34
34
  'obsolete',
35
35
  'obsoleted',
36
36
  'retired',
37
- 'archived',
38
- 'archive',
39
37
  'rejected',
40
38
  'declined',
41
39
  'withdrawn',
@@ -58,6 +56,16 @@ const VOCABULARY = [
58
56
  'wontfix',
59
57
  ],
60
58
  ],
59
+ [
60
+ // A finished round of work kept as it was left: spec-brief archives a brief
61
+ // by writing this word and moving the file. Every spec-* tool reads it as a
62
+ // record rather than as a retired decision - depending on one is normal,
63
+ // its unticked boxes were never going to be ticked, and its links still
64
+ // have to go somewhere (ADR-0011). After retirement, so a brief written
65
+ // `archived, superseded by B-0007` is still retired.
66
+ 'record',
67
+ ['archived', 'archive'],
68
+ ],
61
69
  [
62
70
  'frozen',
63
71
  ['final', 'finalised', 'finalized', 'frozen', 'locked', 'ratified', 'immutable', 'sealed', 'standard', 'published'],
@@ -1 +1 @@
1
- {"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Status vocabulary normalisation.\n *\n * Every specification ecosystem invented its own status words, and no two agree.\n * MADR says `accepted`; Kubernetes KEPs say `implementable`; Rust RFCs say\n * `merged`; a hundred internal wikis say `Live`, `Signed off`, or `DONE ✅`.\n *\n * spec-graph refuses to care. What it needs from a status is one bit - *can this\n * document still absorb an obligation?* - and that bit is recoverable from all\n * of those vocabularies at once. The tables below are the only place in the\n * codebase that knows any ecosystem-specific word, which is what keeps the\n * engine domain-agnostic: supporting a new convention is a table entry, never a\n * rule change.\n */\n\nimport type { Phase, Receptivity } from './types.js';\n\n/**\n * Recognised status words, most terminal first.\n *\n * Order matters. A status of \"accepted, superseded by ADR-0009\" is retired, not\n * active: retirement is terminal, so a retirement word anywhere in the string\n * wins over anything else in it.\n */\nconst VOCABULARY: readonly (readonly [Phase, readonly string[]])[] = [\n [\n 'retired',\n [\n 'superseded',\n // Misspelled in the wild often enough that omitting it would silently\n // mis-classify real documents as active.\n 'superceded',\n 'supersedes-by',\n 'replaced',\n 'replaced-by',\n 'deprecated',\n 'obsolete',\n 'obsoleted',\n 'retired',\n 'archived',\n 'archive',\n 'rejected',\n 'declined',\n 'withdrawn',\n 'abandoned',\n 'cancelled',\n 'canceled',\n 'dropped',\n 'revoked',\n 'reverted',\n 'moved',\n 'historical',\n 'defunct',\n 'inactive',\n 'dead',\n 'void',\n 'closed',\n 'postponed',\n 'deferred',\n 'not-planned',\n 'wontfix',\n ],\n ],\n [\n 'frozen',\n ['final', 'finalised', 'finalized', 'frozen', 'locked', 'ratified', 'immutable', 'sealed', 'standard', 'published'],\n ],\n [\n 'active',\n [\n 'accepted',\n 'active',\n 'approved',\n 'adopted',\n 'agreed',\n 'implementable',\n 'implemented',\n 'implementing',\n 'current',\n 'effective',\n 'in-effect',\n 'enforced',\n 'stable',\n 'merged',\n 'released',\n 'shipped',\n 'live',\n 'done',\n 'complete',\n 'completed',\n 'signed-off',\n 'committed',\n ],\n ],\n [\n 'draft',\n [\n 'draft',\n 'drafting',\n 'proposed',\n 'proposal',\n 'provisional',\n 'prospective',\n 'wip',\n 'work-in-progress',\n 'in-progress',\n 'review',\n 'in-review',\n 'under-review',\n 'reviewing',\n 'discussion',\n 'discussing',\n 'pending',\n 'idea',\n 'exploratory',\n 'candidate',\n 'open',\n 'new',\n 'unreviewed',\n 'rfc',\n 'experimental',\n 'alpha',\n 'beta',\n 'incubating',\n 'provisionally-accepted',\n ],\n ],\n];\n\n/** Path segments that retire every document beneath them. */\nconst RETIRING_DIRECTORIES: ReadonlySet<string> = new Set([\n 'archive',\n 'archived',\n 'attic',\n 'deprecated',\n 'graveyard',\n 'historical',\n 'obsolete',\n 'rejected',\n 'retired',\n 'superseded',\n 'superceded',\n 'withdrawn',\n]);\n\n/** Front-matter keys that may carry a status, in order of preference. */\nexport const STATUS_KEYS: readonly string[] = ['status', 'state', 'stage', 'lifecycle', 'phase', 'adr-status'];\n\n/** Heading names whose body declares the document status. */\nconst STATUS_HEADINGS: ReadonlySet<string> = new Set(['status', 'state', 'stage', 'lifecycle', 'current status']);\n\n/**\n * Reduces a status string to lookup form.\n *\n * Strips Markdown emphasis, badge syntax, emoji and dates, so `**Accepted**`,\n * `` `accepted` ``, `Accepted ✅` and `Accepted (2026-03-01)` all land on the\n * same token.\n */\nexport function normaliseStatus(raw: string): string {\n return raw\n .replace(/<[^>]*>/g, ' ')\n .replace(/[`*_~\"'#]/g, '')\n .replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1')\n .replace(/\\p{Extended_Pictographic}/gu, ' ')\n .replace(/\\d{4}-\\d{2}-\\d{2}/g, ' ')\n .toLowerCase()\n .replace(/[^\\p{L}\\p{N}]+/gu, ' ')\n .trim();\n}\n\n/**\n * Maps a raw status string onto a lifecycle phase.\n *\n * Returns `unknown` rather than guessing when nothing matches: a document with\n * an unrecognised status is not evidence of anything, and inventing a phase for\n * it would produce exactly the confident-but-wrong findings this tool exists to\n * eliminate.\n */\nexport function phaseOf(raw: string | null | undefined): Phase {\n if (raw === null || raw === undefined) return 'unknown';\n const text = normaliseStatus(raw);\n if (text.length === 0) return 'unknown';\n const words = new Set(text.split(' '));\n const hyphenated = text.replace(/ /g, '-');\n\n for (const [phase, terms] of VOCABULARY) {\n for (const term of terms) {\n if (term.includes('-')) {\n if (hyphenated.includes(term)) return phase;\n } else if (words.has(term)) {\n return phase;\n }\n }\n }\n return 'unknown';\n}\n\n/** Whether a document in this phase can take on a new open obligation. */\nexport function receptivityOf(phase: Phase): Receptivity {\n switch (phase) {\n case 'draft':\n case 'active':\n return 'receptive';\n case 'frozen':\n case 'retired':\n // A record was never asking for an obligation, so it cannot take one on.\n // Sealed for the same reason a retired document is, by a different route.\n case 'record':\n return 'sealed';\n case 'unknown':\n return 'unknown';\n }\n}\n\n/** True when the phase means the document no longer binds anybody. */\nexport function isRetired(phase: Phase): boolean {\n return phase === 'retired';\n}\n\n/** True when the heading names a section that declares the document status. */\nexport function isStatusHeading(text: string): boolean {\n return STATUS_HEADINGS.has(text.trim().toLowerCase().replace(/[:*_`]/g, '').trim());\n}\n\n/**\n * Infers retirement from where a file lives.\n *\n * Moving an ADR into `docs/adr/archive/` is the most common way a team retires a\n * decision without touching its front matter, and a graph that misses it will\n * happily let obligations be delegated into the archive.\n */\nexport function phaseFromPath(posixPath: string): Phase {\n const segments = posixPath.toLowerCase().split('/');\n // The file name itself is not a directory; a document called `archive.md` is\n // not retired.\n for (let i = 0; i < segments.length - 1; i += 1) {\n if (RETIRING_DIRECTORIES.has(segments[i] as string)) return 'retired';\n }\n return 'unknown';\n}\n\n/**\n * Pulls a supersession target out of a status string.\n *\n * `Superseded by ADR-0009` is the single most common way a supersession is ever\n * recorded, and it is written in the status field rather than as a link. Reading\n * it here means the relation reaches the graph even in repositories that never\n * adopted an explicit field for it.\n */\nexport function supersessionTargetsIn(raw: string): string[] {\n const out: string[] = [];\n const pattern = /(?:superse[dc]ed|replaced|obsoleted)\\s*(?:by|with|through)?\\s*[:\\-—]?\\s*(.+)$/i;\n const match = pattern.exec(raw.replace(/[`*_]/g, ''));\n if (!match) return out;\n const tail = match[1] as string;\n for (const token of tail.split(/[,;]|\\band\\b/)) {\n const cleaned = token\n .replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1')\n .replace(/[()<>\"']/g, ' ')\n .trim();\n if (cleaned.length > 0 && cleaned.length < 200) out.push(cleaned);\n }\n return out;\n}\n"]}
1
+ {"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Status vocabulary normalisation.\n *\n * Every specification ecosystem invented its own status words, and no two agree.\n * MADR says `accepted`; Kubernetes KEPs say `implementable`; Rust RFCs say\n * `merged`; a hundred internal wikis say `Live`, `Signed off`, or `DONE ✅`.\n *\n * spec-graph refuses to care. What it needs from a status is one bit - *can this\n * document still absorb an obligation?* - and that bit is recoverable from all\n * of those vocabularies at once. The tables below are the only place in the\n * codebase that knows any ecosystem-specific word, which is what keeps the\n * engine domain-agnostic: supporting a new convention is a table entry, never a\n * rule change.\n */\n\nimport type { Phase, Receptivity } from './types.js';\n\n/**\n * Recognised status words, most terminal first.\n *\n * Order matters. A status of \"accepted, superseded by ADR-0009\" is retired, not\n * active: retirement is terminal, so a retirement word anywhere in the string\n * wins over anything else in it.\n */\nconst VOCABULARY: readonly (readonly [Phase, readonly string[]])[] = [\n [\n 'retired',\n [\n 'superseded',\n // Misspelled in the wild often enough that omitting it would silently\n // mis-classify real documents as active.\n 'superceded',\n 'supersedes-by',\n 'replaced',\n 'replaced-by',\n 'deprecated',\n 'obsolete',\n 'obsoleted',\n 'retired',\n 'rejected',\n 'declined',\n 'withdrawn',\n 'abandoned',\n 'cancelled',\n 'canceled',\n 'dropped',\n 'revoked',\n 'reverted',\n 'moved',\n 'historical',\n 'defunct',\n 'inactive',\n 'dead',\n 'void',\n 'closed',\n 'postponed',\n 'deferred',\n 'not-planned',\n 'wontfix',\n ],\n ],\n [\n // A finished round of work kept as it was left: spec-brief archives a brief\n // by writing this word and moving the file. Every spec-* tool reads it as a\n // record rather than as a retired decision - depending on one is normal,\n // its unticked boxes were never going to be ticked, and its links still\n // have to go somewhere (ADR-0011). After retirement, so a brief written\n // `archived, superseded by B-0007` is still retired.\n 'record',\n ['archived', 'archive'],\n ],\n [\n 'frozen',\n ['final', 'finalised', 'finalized', 'frozen', 'locked', 'ratified', 'immutable', 'sealed', 'standard', 'published'],\n ],\n [\n 'active',\n [\n 'accepted',\n 'active',\n 'approved',\n 'adopted',\n 'agreed',\n 'implementable',\n 'implemented',\n 'implementing',\n 'current',\n 'effective',\n 'in-effect',\n 'enforced',\n 'stable',\n 'merged',\n 'released',\n 'shipped',\n 'live',\n 'done',\n 'complete',\n 'completed',\n 'signed-off',\n 'committed',\n ],\n ],\n [\n 'draft',\n [\n 'draft',\n 'drafting',\n 'proposed',\n 'proposal',\n 'provisional',\n 'prospective',\n 'wip',\n 'work-in-progress',\n 'in-progress',\n 'review',\n 'in-review',\n 'under-review',\n 'reviewing',\n 'discussion',\n 'discussing',\n 'pending',\n 'idea',\n 'exploratory',\n 'candidate',\n 'open',\n 'new',\n 'unreviewed',\n 'rfc',\n 'experimental',\n 'alpha',\n 'beta',\n 'incubating',\n 'provisionally-accepted',\n ],\n ],\n];\n\n/** Path segments that retire every document beneath them. */\nconst RETIRING_DIRECTORIES: ReadonlySet<string> = new Set([\n 'archive',\n 'archived',\n 'attic',\n 'deprecated',\n 'graveyard',\n 'historical',\n 'obsolete',\n 'rejected',\n 'retired',\n 'superseded',\n 'superceded',\n 'withdrawn',\n]);\n\n/** Front-matter keys that may carry a status, in order of preference. */\nexport const STATUS_KEYS: readonly string[] = ['status', 'state', 'stage', 'lifecycle', 'phase', 'adr-status'];\n\n/** Heading names whose body declares the document status. */\nconst STATUS_HEADINGS: ReadonlySet<string> = new Set(['status', 'state', 'stage', 'lifecycle', 'current status']);\n\n/**\n * Reduces a status string to lookup form.\n *\n * Strips Markdown emphasis, badge syntax, emoji and dates, so `**Accepted**`,\n * `` `accepted` ``, `Accepted ✅` and `Accepted (2026-03-01)` all land on the\n * same token.\n */\nexport function normaliseStatus(raw: string): string {\n return raw\n .replace(/<[^>]*>/g, ' ')\n .replace(/[`*_~\"'#]/g, '')\n .replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1')\n .replace(/\\p{Extended_Pictographic}/gu, ' ')\n .replace(/\\d{4}-\\d{2}-\\d{2}/g, ' ')\n .toLowerCase()\n .replace(/[^\\p{L}\\p{N}]+/gu, ' ')\n .trim();\n}\n\n/**\n * Maps a raw status string onto a lifecycle phase.\n *\n * Returns `unknown` rather than guessing when nothing matches: a document with\n * an unrecognised status is not evidence of anything, and inventing a phase for\n * it would produce exactly the confident-but-wrong findings this tool exists to\n * eliminate.\n */\nexport function phaseOf(raw: string | null | undefined): Phase {\n if (raw === null || raw === undefined) return 'unknown';\n const text = normaliseStatus(raw);\n if (text.length === 0) return 'unknown';\n const words = new Set(text.split(' '));\n const hyphenated = text.replace(/ /g, '-');\n\n for (const [phase, terms] of VOCABULARY) {\n for (const term of terms) {\n if (term.includes('-')) {\n if (hyphenated.includes(term)) return phase;\n } else if (words.has(term)) {\n return phase;\n }\n }\n }\n return 'unknown';\n}\n\n/** Whether a document in this phase can take on a new open obligation. */\nexport function receptivityOf(phase: Phase): Receptivity {\n switch (phase) {\n case 'draft':\n case 'active':\n return 'receptive';\n case 'frozen':\n case 'retired':\n // A record was never asking for an obligation, so it cannot take one on.\n // Sealed for the same reason a retired document is, by a different route.\n case 'record':\n return 'sealed';\n case 'unknown':\n return 'unknown';\n }\n}\n\n/** True when the phase means the document no longer binds anybody. */\nexport function isRetired(phase: Phase): boolean {\n return phase === 'retired';\n}\n\n/** True when the heading names a section that declares the document status. */\nexport function isStatusHeading(text: string): boolean {\n return STATUS_HEADINGS.has(text.trim().toLowerCase().replace(/[:*_`]/g, '').trim());\n}\n\n/**\n * Infers retirement from where a file lives.\n *\n * Moving an ADR into `docs/adr/archive/` is the most common way a team retires a\n * decision without touching its front matter, and a graph that misses it will\n * happily let obligations be delegated into the archive.\n */\nexport function phaseFromPath(posixPath: string): Phase {\n const segments = posixPath.toLowerCase().split('/');\n // The file name itself is not a directory; a document called `archive.md` is\n // not retired.\n for (let i = 0; i < segments.length - 1; i += 1) {\n if (RETIRING_DIRECTORIES.has(segments[i] as string)) return 'retired';\n }\n return 'unknown';\n}\n\n/**\n * Pulls a supersession target out of a status string.\n *\n * `Superseded by ADR-0009` is the single most common way a supersession is ever\n * recorded, and it is written in the status field rather than as a link. Reading\n * it here means the relation reaches the graph even in repositories that never\n * adopted an explicit field for it.\n */\nexport function supersessionTargetsIn(raw: string): string[] {\n const out: string[] = [];\n const pattern = /(?:superse[dc]ed|replaced|obsoleted)\\s*(?:by|with|through)?\\s*[:\\-—]?\\s*(.+)$/i;\n const match = pattern.exec(raw.replace(/[`*_]/g, ''));\n if (!match) return out;\n const tail = match[1] as string;\n for (const token of tail.split(/[,;]|\\band\\b/)) {\n const cleaned = token\n .replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1')\n .replace(/[()<>\"']/g, ' ')\n .trim();\n if (cleaned.length > 0 && cleaned.length < 200) out.push(cleaned);\n }\n return out;\n}\n"]}
@@ -1,166 +1,58 @@
1
1
  /**
2
- * A structural Markdown scanner.
2
+ * What spec-graph reads out of a Markdown document.
3
3
  *
4
- * This is deliberately **not** a CommonMark implementation. spec-graph needs six
5
- * things from a document - front matter, headings, list items with their
6
- * continuations, HTML comments, links, and a reliable map of what is code - and
7
- * a full parser would cost a dependency tree, an AST walk, and a position
8
- * mapping layer to get back the offsets we want in the first place.
4
+ * The scan is spec-core's, copied into `src/vendor/spec-core/markdown/`: one
5
+ * pass that is exact about code and comments, as CommonMark is, and simple about
6
+ * the rest (ADR-0001). It started as this file, and the guarantees it was
7
+ * written for came with it: code never counts, items are blocks and not lines,
8
+ * and everything carries absolute offsets.
9
9
  *
10
- * What the scanner does guarantee is the part that makes regex-based spec
11
- * linters lie:
10
+ * What stays here is what spec-graph decides about the scan, which no other
11
+ * tool has to agree with: which links cite something, which anchors a heading
12
+ * answers to, and which lines are Markdown at all.
13
+ */
14
+ import type { FrontMatterBlock, Heading, Link, MarkdownScan, ScannedLine } from './vendor/spec-core/markdown/index.js';
15
+ export { scanMarkdown, slugify } from './vendor/spec-core/markdown/index.js';
16
+ export type { Heading, HtmlComment, Link, LinkForm, ListItem, ScannedLine, Table, TableCell, TableRow, } from './vendor/spec-core/markdown/index.js';
17
+ export type { Range } from './vendor/spec-core/text/index.js';
18
+ /** A scanned document, under the name the API has always given it. */
19
+ export type ScannedDocument = MarkdownScan;
20
+ /** The front-matter block at the top of a document, under the name the API has always given it. */
21
+ export type FrontMatter = FrontMatterBlock;
22
+ /**
23
+ * Whether a line's content is Markdown.
24
+ *
25
+ * Code, the four raw-text HTML elements and front matter are not, for the same
26
+ * reason: a heading, a status or an item written in one is an example or data,
27
+ * and never a statement the document makes.
28
+ */
29
+ export declare function isMarkdownLine(line: ScannedLine): boolean;
30
+ /**
31
+ * Whether a line holds a comment and nothing else.
32
+ *
33
+ * For a reader that takes the first line of a section as its value, which is
34
+ * what a status section is. A template's hint written above the value - `<!--
35
+ * proposed | accepted -->` - is not the value, and neither is a directive. A
36
+ * line that goes on past its comment, `<!-- hint --> Accepted`, is still read.
37
+ */
38
+ export declare function isOnlyComment(scanned: ScannedDocument, line: ScannedLine): boolean;
39
+ /**
40
+ * The links that cite something.
41
+ *
42
+ * An image shows a file and cites nothing: a diagram of a decision is not a
43
+ * dependency on it, and a missing picture is a broken page, not a broken
44
+ * relation. So images are not references, as they never were. A wiki embed,
45
+ * `![[0007-sharding]]`, is the exception - it transcludes the note it names,
46
+ * which is the strongest citation a wiki can write - and spec-graph has always
47
+ * read it as one.
48
+ */
49
+ export declare function referenceLinks(scanned: ScannedDocument): Link[];
50
+ /**
51
+ * The anchors a set of headings answers to.
12
52
  *
13
- * - **Code never counts.** Fenced blocks, indented blocks and inline spans are
14
- * masked before a single link is extracted, so an example in a code sample
15
- * never becomes a graph edge.
16
- * - **Items are blocks, not lines.** A list item owns its wrapped continuation
17
- * lines and its nested content, so a resolution written on the second line of
18
- * a bullet is found instead of missed.
19
- * - **Everything carries absolute offsets.** No re-scanning, no drift between
20
- * the text a rule matched and the position it reports.
53
+ * Each heading's slug, and the anchor GitHub gives it, which is the slug with
54
+ * `-1`, `-2` and so on for the second and later headings that slug alike. A
55
+ * link written against the rendered page uses the anchor; one written by hand
56
+ * uses the slug, and for any heading but a repeat the two are one.
21
57
  */
22
- import { type LineIndex } from './source.js';
23
- export interface Range {
24
- readonly start: number;
25
- readonly end: number;
26
- }
27
- export interface FrontMatter {
28
- /** The body between the delimiters, exclusive. */
29
- readonly raw: string;
30
- /** Offset of the first character of `raw`. */
31
- readonly start: number;
32
- readonly end: number;
33
- /** Offset just past the closing delimiter line. */
34
- readonly bodyStart: number;
35
- }
36
- export interface ScannedLine {
37
- /** 1-based. */
38
- readonly line: number;
39
- /** Offset of the raw line start. */
40
- readonly start: number;
41
- /** Offset just past the line, excluding its terminator. */
42
- readonly end: number;
43
- /** Offset of the first character after any block-quote markers. */
44
- readonly contentStart: number;
45
- /** Line text after block-quote markers, indentation intact. */
46
- readonly content: string;
47
- /** Indentation of `content`, tabs counted as four columns. */
48
- readonly indent: number;
49
- readonly blank: boolean;
50
- readonly quoteDepth: number;
51
- /** Inside a fenced or indented code block, fence delimiters included. */
52
- readonly code: boolean;
53
- }
54
- export interface Heading {
55
- readonly level: number;
56
- readonly text: string;
57
- /** GitHub-compatible anchor slug. */
58
- readonly slug: string;
59
- readonly start: number;
60
- readonly end: number;
61
- readonly line: number;
62
- }
63
- export interface ListItem {
64
- /** The whole block: marker line plus continuations and nested content. */
65
- readonly start: number;
66
- readonly end: number;
67
- /** Offset of the list marker itself. */
68
- readonly markerStart: number;
69
- readonly marker: string;
70
- /** Offset where the item text begins, after marker and any checkbox. */
71
- readonly textStart: number;
72
- /** The character inside `[ ]`, or `null` when the item has no checkbox. */
73
- readonly checkbox: string | null;
74
- readonly checkboxStart: number | null;
75
- /** First line of item text, trimmed. */
76
- readonly firstLine: string;
77
- /** Full item text including continuations and nested content. */
78
- readonly body: string;
79
- /**
80
- * `body` with code and comments blanked out, same length and offsets.
81
- *
82
- * Anything that searches item text for meaning - resolution markers above
83
- * all - must read this rather than `body`, or a fenced example nested under
84
- * the item will close it.
85
- */
86
- readonly maskedBody: string;
87
- readonly line: number;
88
- /** How many list items enclose this one. Top-level items are `0`. */
89
- readonly depth: number;
90
- readonly indent: number;
91
- }
92
- export interface HtmlComment {
93
- readonly start: number;
94
- readonly end: number;
95
- /** Text between `<!--` and `-->`. */
96
- readonly inner: string;
97
- readonly innerStart: number;
98
- readonly line: number;
99
- }
100
- export type LinkForm = 'inline' | 'reference' | 'shortcut' | 'autolink' | 'wiki' | 'definition';
101
- export interface Link {
102
- /** Visible label. Empty for autolinks and definitions. */
103
- readonly text: string;
104
- /** Destination as written: a path or a URL. */
105
- readonly target: string;
106
- /** Offset of the whole construct. */
107
- readonly start: number;
108
- readonly end: number;
109
- /**
110
- * Offset of `target` inside the source, for precise diagnostics.
111
- *
112
- * For a reference link this is inside the definition, not inside the use:
113
- * `[design][one]` has no destination of its own, and the line a human edits
114
- * to fix it is the one that says what `one` points at.
115
- */
116
- readonly targetStart: number;
117
- /**
118
- * The reference label, for the two forms written with one.
119
- *
120
- * `null` everywhere else. Kept because `target` is the destination the label
121
- * stands for, and a report quoting `[design][docs/gone.md]` would be quoting
122
- * something the author never wrote.
123
- */
124
- readonly label: string | null;
125
- readonly form: LinkForm;
126
- readonly line: number;
127
- }
128
- export interface TableCell {
129
- /** Cell text as written, trimmed. */
130
- readonly text: string;
131
- /** Offset of the trimmed text, so a finding can point at the cell itself. */
132
- readonly start: number;
133
- readonly end: number;
134
- }
135
- export interface TableRow {
136
- readonly cells: readonly TableCell[];
137
- readonly start: number;
138
- readonly end: number;
139
- readonly line: number;
140
- }
141
- export interface Table {
142
- readonly start: number;
143
- readonly end: number;
144
- /** Header cells, trimmed. A table without a header row is not a table. */
145
- readonly headers: readonly TableCell[];
146
- readonly rows: readonly TableRow[];
147
- }
148
- export interface ScannedDocument {
149
- readonly text: string;
150
- readonly index: LineIndex;
151
- readonly frontMatter: FrontMatter | null;
152
- /** Offset where the body starts, after any front matter. */
153
- readonly bodyStart: number;
154
- readonly lines: readonly ScannedLine[];
155
- readonly headings: readonly Heading[];
156
- readonly listItems: readonly ListItem[];
157
- readonly comments: readonly HtmlComment[];
158
- readonly links: readonly Link[];
159
- readonly tables: readonly Table[];
160
- /** Code and comments blanked out, offsets and line breaks preserved. */
161
- readonly masked: string;
162
- /** True when the offset falls inside code, a comment, or front matter. */
163
- isMasked(offset: number): boolean;
164
- }
165
- export declare function scanMarkdown(source: string): ScannedDocument;
166
- export declare function slugify(text: string): string;
58
+ export declare function anchorsOf(headings: readonly Heading[]): Set<string>;