@mortice/mapwright 0.8.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 (166) hide show
  1. package/CHANGELOG.md +161 -0
  2. package/LICENSE +21 -0
  3. package/README.md +262 -0
  4. package/dist/catalogue/canonicalisation.d.ts +36 -0
  5. package/dist/catalogue/canonicalisation.js +262 -0
  6. package/dist/catalogue/config.d.ts +13 -0
  7. package/dist/catalogue/config.js +77 -0
  8. package/dist/catalogue/deterministic.d.ts +3 -0
  9. package/dist/catalogue/deterministic.js +25 -0
  10. package/dist/catalogue/diagnostics.d.ts +2 -0
  11. package/dist/catalogue/diagnostics.js +34 -0
  12. package/dist/catalogue/evidence.d.ts +1 -0
  13. package/dist/catalogue/evidence.js +10 -0
  14. package/dist/catalogue/examples.d.ts +3 -0
  15. package/dist/catalogue/examples.js +20 -0
  16. package/dist/catalogue/identity.d.ts +61 -0
  17. package/dist/catalogue/identity.js +114 -0
  18. package/dist/catalogue/ignore.d.ts +4 -0
  19. package/dist/catalogue/ignore.js +29 -0
  20. package/dist/catalogue/indexer.d.ts +20 -0
  21. package/dist/catalogue/indexer.js +1393 -0
  22. package/dist/catalogue/linkage.d.ts +16 -0
  23. package/dist/catalogue/linkage.js +419 -0
  24. package/dist/catalogue/moduleResolution.d.ts +4 -0
  25. package/dist/catalogue/moduleResolution.js +67 -0
  26. package/dist/catalogue/ordering.d.ts +13 -0
  27. package/dist/catalogue/ordering.js +86 -0
  28. package/dist/catalogue/packages.d.ts +12 -0
  29. package/dist/catalogue/packages.js +475 -0
  30. package/dist/catalogue/pythonReExports.d.ts +7 -0
  31. package/dist/catalogue/pythonReExports.js +113 -0
  32. package/dist/catalogue/resolveRefs.d.ts +40 -0
  33. package/dist/catalogue/resolveRefs.js +284 -0
  34. package/dist/catalogue/scanner.d.ts +8 -0
  35. package/dist/catalogue/scanner.js +99 -0
  36. package/dist/catalogue/schema.d.ts +289 -0
  37. package/dist/catalogue/schema.js +1 -0
  38. package/dist/catalogue/store.d.ts +41 -0
  39. package/dist/catalogue/store.js +209 -0
  40. package/dist/catalogue/templates.d.ts +18 -0
  41. package/dist/catalogue/templates.js +158 -0
  42. package/dist/catalogue/version.d.ts +12 -0
  43. package/dist/catalogue/version.js +30 -0
  44. package/dist/cli/commands/adoptionPlan.d.ts +8 -0
  45. package/dist/cli/commands/adoptionPlan.js +24 -0
  46. package/dist/cli/commands/auditDocs.d.ts +8 -0
  47. package/dist/cli/commands/auditDocs.js +24 -0
  48. package/dist/cli/commands/changeImpact.d.ts +10 -0
  49. package/dist/cli/commands/changeImpact.js +36 -0
  50. package/dist/cli/commands/changes.d.ts +12 -0
  51. package/dist/cli/commands/changes.js +31 -0
  52. package/dist/cli/commands/check.d.ts +9 -0
  53. package/dist/cli/commands/check.js +4 -0
  54. package/dist/cli/commands/compatibility.d.ts +10 -0
  55. package/dist/cli/commands/compatibility.js +43 -0
  56. package/dist/cli/commands/diff.d.ts +31 -0
  57. package/dist/cli/commands/diff.js +118 -0
  58. package/dist/cli/commands/dogfood.d.ts +8 -0
  59. package/dist/cli/commands/dogfood.js +24 -0
  60. package/dist/cli/commands/drift.d.ts +8 -0
  61. package/dist/cli/commands/drift.js +13 -0
  62. package/dist/cli/commands/index.d.ts +9 -0
  63. package/dist/cli/commands/index.js +9 -0
  64. package/dist/cli/commands/indexWorkspace.d.ts +8 -0
  65. package/dist/cli/commands/indexWorkspace.js +23 -0
  66. package/dist/cli/commands/recommendConfig.d.ts +7 -0
  67. package/dist/cli/commands/recommendConfig.js +20 -0
  68. package/dist/cli/commands/schema.d.ts +1 -0
  69. package/dist/cli/commands/schema.js +37 -0
  70. package/dist/cli/commands/template.d.ts +5 -0
  71. package/dist/cli/commands/template.js +44 -0
  72. package/dist/cli/commands/validate.d.ts +9 -0
  73. package/dist/cli/commands/validate.js +85 -0
  74. package/dist/cli/index.d.ts +2 -0
  75. package/dist/cli/index.js +211 -0
  76. package/dist/comparison/artefactValidate.d.ts +19 -0
  77. package/dist/comparison/artefactValidate.js +334 -0
  78. package/dist/comparison/candidates.d.ts +12 -0
  79. package/dist/comparison/candidates.js +391 -0
  80. package/dist/comparison/compare.d.ts +15 -0
  81. package/dist/comparison/compare.js +240 -0
  82. package/dist/comparison/compatibility.d.ts +26 -0
  83. package/dist/comparison/compatibility.js +316 -0
  84. package/dist/comparison/drift.d.ts +34 -0
  85. package/dist/comparison/drift.js +71 -0
  86. package/dist/comparison/identity.d.ts +30 -0
  87. package/dist/comparison/identity.js +73 -0
  88. package/dist/comparison/impact.d.ts +14 -0
  89. package/dist/comparison/impact.js +291 -0
  90. package/dist/comparison/index.d.ts +6 -0
  91. package/dist/comparison/index.js +6 -0
  92. package/dist/comparison/integrity.d.ts +12 -0
  93. package/dist/comparison/integrity.js +199 -0
  94. package/dist/comparison/ordering.d.ts +4 -0
  95. package/dist/comparison/ordering.js +69 -0
  96. package/dist/comparison/projections.d.ts +19 -0
  97. package/dist/comparison/projections.js +185 -0
  98. package/dist/comparison/relationshipPolicy.d.ts +19 -0
  99. package/dist/comparison/relationshipPolicy.js +98 -0
  100. package/dist/comparison/schema.d.ts +178 -0
  101. package/dist/comparison/schema.js +16 -0
  102. package/dist/comparison/store.d.ts +58 -0
  103. package/dist/comparison/store.js +462 -0
  104. package/dist/comparison/validate.d.ts +23 -0
  105. package/dist/comparison/validate.js +137 -0
  106. package/dist/comparison/version.d.ts +9 -0
  107. package/dist/comparison/version.js +11 -0
  108. package/dist/extractors/docTags.d.ts +9 -0
  109. package/dist/extractors/docTags.js +106 -0
  110. package/dist/extractors/generic.d.ts +5 -0
  111. package/dist/extractors/generic.js +3 -0
  112. package/dist/extractors/javascript.d.ts +3 -0
  113. package/dist/extractors/javascript.js +4 -0
  114. package/dist/extractors/markdown.d.ts +7 -0
  115. package/dist/extractors/markdown.js +269 -0
  116. package/dist/extractors/python.d.ts +7 -0
  117. package/dist/extractors/python.js +314 -0
  118. package/dist/extractors/typescript.d.ts +7 -0
  119. package/dist/extractors/typescript.js +387 -0
  120. package/dist/index.d.ts +2 -0
  121. package/dist/index.js +2 -0
  122. package/dist/mcp/resources.d.ts +18 -0
  123. package/dist/mcp/resources.js +57 -0
  124. package/dist/mcp/server.d.ts +2 -0
  125. package/dist/mcp/server.js +95 -0
  126. package/dist/mcp/tools.d.ts +29 -0
  127. package/dist/mcp/tools.js +902 -0
  128. package/dist/queries/adoption.d.ts +62 -0
  129. package/dist/queries/adoption.js +366 -0
  130. package/dist/queries/capabilities.d.ts +45 -0
  131. package/dist/queries/capabilities.js +124 -0
  132. package/dist/queries/changes.d.ts +33 -0
  133. package/dist/queries/changes.js +53 -0
  134. package/dist/queries/dependencies.d.ts +17 -0
  135. package/dist/queries/dependencies.js +94 -0
  136. package/dist/queries/dogfood.d.ts +50 -0
  137. package/dist/queries/dogfood.js +116 -0
  138. package/dist/queries/editingContext.d.ts +84 -0
  139. package/dist/queries/editingContext.js +240 -0
  140. package/dist/queries/examples.d.ts +8 -0
  141. package/dist/queries/examples.js +16 -0
  142. package/dist/queries/files.d.ts +8 -0
  143. package/dist/queries/files.js +14 -0
  144. package/dist/queries/lists.d.ts +94 -0
  145. package/dist/queries/lists.js +184 -0
  146. package/dist/queries/overview.d.ts +2 -0
  147. package/dist/queries/overview.js +8 -0
  148. package/dist/queries/publicApis.d.ts +60 -0
  149. package/dist/queries/publicApis.js +120 -0
  150. package/dist/queries/ranking.d.ts +67 -0
  151. package/dist/queries/ranking.js +387 -0
  152. package/dist/queries/recommendConfig.d.ts +47 -0
  153. package/dist/queries/recommendConfig.js +123 -0
  154. package/dist/queries/relationships.d.ts +5 -0
  155. package/dist/queries/relationships.js +15 -0
  156. package/dist/queries/reuseCandidates.d.ts +34 -0
  157. package/dist/queries/reuseCandidates.js +181 -0
  158. package/dist/queries/symbols.d.ts +40 -0
  159. package/dist/queries/symbols.js +41 -0
  160. package/dist/security/pathPolicy.d.ts +12 -0
  161. package/dist/security/pathPolicy.js +46 -0
  162. package/dist/security/secretPatterns.d.ts +1 -0
  163. package/dist/security/secretPatterns.js +4 -0
  164. package/dist/security/sourceAccess.d.ts +12 -0
  165. package/dist/security/sourceAccess.js +35 -0
  166. package/package.json +60 -0
@@ -0,0 +1,43 @@
1
+ import path from "node:path";
2
+ import { loadComparisonArtefact } from "../../comparison/store.js";
3
+ import { getCompatibilityReport } from "../../queries/changes.js";
4
+ const SEVERITY = {
5
+ breaking: 0,
6
+ potentially_breaking: 1,
7
+ unknown: 2,
8
+ non_breaking: 3,
9
+ documentation_only: 4,
10
+ not_applicable: 5
11
+ };
12
+ export function runCompatibilityCommand(options) {
13
+ if (!options.comparisonDir) {
14
+ return {
15
+ output: { ok: false, error: { code: "usage_error", message: "--comparison-dir is required" } },
16
+ exitCode: 2
17
+ };
18
+ }
19
+ const loaded = loadComparisonArtefact(path.resolve(options.comparisonDir));
20
+ if (!loaded.ok) {
21
+ return { output: { ok: false, error: loaded.error }, exitCode: 3 };
22
+ }
23
+ const report = getCompatibilityReport(loaded.comparison, {
24
+ offset: options.offset,
25
+ limit: options.limit
26
+ });
27
+ const failOn = options.failOn ?? "never";
28
+ const aggregate = report.aggregate;
29
+ let exitCode = 0;
30
+ if (failOn === "breaking" && aggregate === "breaking")
31
+ exitCode = 1;
32
+ if (failOn === "potentially-breaking" && aggregate && SEVERITY[aggregate] <= SEVERITY.potentially_breaking) {
33
+ exitCode = 1;
34
+ }
35
+ if (failOn === "unknown" && aggregate && SEVERITY[aggregate] <= SEVERITY.unknown)
36
+ exitCode = 1;
37
+ if (failOn === "any-change" || failOn === "any-public-change") {
38
+ if ((loaded.comparison.manifest.counts.added + loaded.comparison.manifest.counts.removed + loaded.comparison.manifest.counts.modified) > 0) {
39
+ exitCode = 1;
40
+ }
41
+ }
42
+ return { output: { ok: true, data: report }, exitCode };
43
+ }
@@ -0,0 +1,31 @@
1
+ export type FailOn = "never" | "unknown" | "potentially-breaking" | "breaking" | "any-public-change" | "any-change";
2
+ export declare function hasPublicFacingChange(input: {
3
+ changes: Array<{
4
+ domain: string;
5
+ status: string;
6
+ }>;
7
+ candidates: Array<{
8
+ domain: string;
9
+ }>;
10
+ compatibilityFindings: Array<{
11
+ ruleId: string;
12
+ classification: string;
13
+ }>;
14
+ }): boolean;
15
+ export declare function runDiffCommand(options: {
16
+ baseWorkspace: string;
17
+ baseCatalogueDir: string;
18
+ headWorkspace: string;
19
+ headCatalogueDir: string;
20
+ writeDir?: string;
21
+ failOn?: FailOn;
22
+ }): {
23
+ output: Record<string, unknown>;
24
+ exitCode: number;
25
+ };
26
+ export declare function runLoadComparisonCommand(options: {
27
+ comparisonDir: string;
28
+ }): {
29
+ output: Record<string, unknown>;
30
+ exitCode: number;
31
+ };
@@ -0,0 +1,118 @@
1
+ import path from "node:path";
2
+ import { loadCataloguePair } from "../../comparison/validate.js";
3
+ import { compareCatalogues } from "../../comparison/compare.js";
4
+ import { writeComparisonArtefact, loadComparisonArtefact } from "../../comparison/store.js";
5
+ import { DEFAULT_COMPARISON_OPTIONS } from "../../comparison/schema.js";
6
+ const SEVERITY = {
7
+ breaking: 0,
8
+ potentially_breaking: 1,
9
+ unknown: 2,
10
+ non_breaking: 3,
11
+ documentation_only: 4,
12
+ not_applicable: 5
13
+ };
14
+ export function hasPublicFacingChange(input) {
15
+ if (input.changes.some((c) => c.domain === "publicApis" && c.status !== "unchanged")) {
16
+ return true;
17
+ }
18
+ if (input.candidates.some((c) => c.domain === "publicApis")) {
19
+ return true;
20
+ }
21
+ if (input.compatibilityFindings.some((f) => f.ruleId.startsWith("public-") ||
22
+ f.ruleId.startsWith("python-console-script") ||
23
+ f.ruleId.startsWith("stability-"))) {
24
+ return true;
25
+ }
26
+ if (input.changes.some((c) => c.domain === "packages" &&
27
+ c.status === "modified" &&
28
+ input.compatibilityFindings.some((f) => f.ruleId.startsWith("python-console-script")))) {
29
+ return true;
30
+ }
31
+ return false;
32
+ }
33
+ function thresholdReached(failOn, aggregate, counts, publicFacing) {
34
+ if (failOn === "never")
35
+ return false;
36
+ if (failOn === "any-change") {
37
+ return counts.added + counts.removed + counts.modified > 0;
38
+ }
39
+ if (failOn === "any-public-change") {
40
+ return publicFacing;
41
+ }
42
+ if (!aggregate)
43
+ return false;
44
+ if (failOn === "breaking")
45
+ return aggregate === "breaking";
46
+ if (failOn === "potentially-breaking") {
47
+ return SEVERITY[aggregate] <= SEVERITY.potentially_breaking;
48
+ }
49
+ if (failOn === "unknown") {
50
+ return SEVERITY[aggregate] <= SEVERITY.unknown;
51
+ }
52
+ return false;
53
+ }
54
+ export function runDiffCommand(options) {
55
+ const pair = loadCataloguePair({
56
+ baseWorkspaceRoot: path.resolve(options.baseWorkspace),
57
+ baseCatalogueDir: options.baseCatalogueDir,
58
+ headWorkspaceRoot: path.resolve(options.headWorkspace),
59
+ headCatalogueDir: options.headCatalogueDir
60
+ });
61
+ if (!pair.ok) {
62
+ const code = pair.error.code === "comparison_path_rejected" ? 4 : 3;
63
+ return { output: { ok: false, error: pair.error }, exitCode: code };
64
+ }
65
+ const compared = compareCatalogues(pair.base, pair.head, DEFAULT_COMPARISON_OPTIONS);
66
+ if (!compared.ok) {
67
+ const code = compared.error.code === "comparison_path_rejected" ? 4 : 3;
68
+ return { output: { ok: false, error: compared.error }, exitCode: code };
69
+ }
70
+ if (options.writeDir) {
71
+ const written = writeComparisonArtefact(path.resolve(options.writeDir), compared.comparison);
72
+ if (!written.ok) {
73
+ return {
74
+ output: { ok: false, error: written.error },
75
+ exitCode: written.error.code === "comparison_path_rejected" ? 4 : 3
76
+ };
77
+ }
78
+ }
79
+ const failOn = options.failOn ?? "never";
80
+ const publicFacing = hasPublicFacingChange(compared.comparison);
81
+ const hit = thresholdReached(failOn, compared.comparison.manifest.aggregateCompatibility, compared.comparison.manifest.counts, publicFacing);
82
+ return {
83
+ output: {
84
+ ok: true,
85
+ data: {
86
+ comparisonId: compared.comparison.manifest.comparisonId,
87
+ counts: compared.comparison.manifest.counts,
88
+ aggregateCompatibility: compared.comparison.manifest.aggregateCompatibility,
89
+ baseCatalogueId: compared.comparison.manifest.baseCatalogueId,
90
+ headCatalogueId: compared.comparison.manifest.headCatalogueId,
91
+ baseGeneratorVersion: compared.comparison.manifest.baseGeneratorVersion,
92
+ headGeneratorVersion: compared.comparison.manifest.headGeneratorVersion,
93
+ warnings: compared.comparison.warnings ?? []
94
+ }
95
+ },
96
+ exitCode: hit ? 1 : 0
97
+ };
98
+ }
99
+ export function runLoadComparisonCommand(options) {
100
+ const loaded = loadComparisonArtefact(path.resolve(options.comparisonDir));
101
+ if (!loaded.ok) {
102
+ return {
103
+ output: { ok: false, error: loaded.error },
104
+ exitCode: loaded.error.code === "comparison_path_rejected" ? 4 : 3
105
+ };
106
+ }
107
+ return {
108
+ output: {
109
+ ok: true,
110
+ data: {
111
+ comparisonId: loaded.comparison.manifest.comparisonId,
112
+ counts: loaded.comparison.manifest.counts,
113
+ aggregateCompatibility: loaded.comparison.manifest.aggregateCompatibility
114
+ }
115
+ },
116
+ exitCode: 0
117
+ };
118
+ }
@@ -0,0 +1,8 @@
1
+ export interface DogfoodCommandOptions {
2
+ workspace: string;
3
+ config?: string;
4
+ mode?: "committed" | "local" | "memory";
5
+ maxDiagnostics?: number;
6
+ maxGaps?: number;
7
+ }
8
+ export declare function runDogfoodCommand(options: DogfoodCommandOptions): Record<string, unknown>;
@@ -0,0 +1,24 @@
1
+ import path from "node:path";
2
+ import { indexWorkspace } from "../../catalogue/indexer.js";
3
+ import { getDogfoodReport } from "../../queries/dogfood.js";
4
+ export function runDogfoodCommand(options) {
5
+ const workspaceRoot = path.resolve(options.workspace);
6
+ const { snapshot } = indexWorkspace({
7
+ workspaceRoot,
8
+ configPath: options.config,
9
+ mode: options.mode ?? "local",
10
+ write: false
11
+ });
12
+ return {
13
+ ok: true,
14
+ data: getDogfoodReport(snapshot, {
15
+ workspace: workspaceRoot,
16
+ maxDiagnostics: options.maxDiagnostics,
17
+ maxGaps: options.maxGaps
18
+ }),
19
+ warnings: [],
20
+ provenance: {
21
+ source: "mapwright"
22
+ }
23
+ };
24
+ }
@@ -0,0 +1,8 @@
1
+ export declare function runDriftCommand(options: {
2
+ workspace: string;
3
+ catalogueDir?: string;
4
+ config?: string;
5
+ }): {
6
+ output: Record<string, unknown>;
7
+ exitCode: number;
8
+ };
@@ -0,0 +1,13 @@
1
+ import path from "node:path";
2
+ import { checkCatalogueDrift } from "../../comparison/drift.js";
3
+ export function runDriftCommand(options) {
4
+ const result = checkCatalogueDrift({
5
+ workspaceRoot: path.resolve(options.workspace),
6
+ catalogueDir: options.catalogueDir,
7
+ configPath: options.config
8
+ });
9
+ if (!result.ok) {
10
+ return { output: { ok: false, error: result.error }, exitCode: 3 };
11
+ }
12
+ return { output: { ok: true, data: result.data }, exitCode: 0 };
13
+ }
@@ -0,0 +1,9 @@
1
+ export * from "./indexWorkspace.js";
2
+ export * from "./validate.js";
3
+ export * from "./check.js";
4
+ export * from "./schema.js";
5
+ export * from "./auditDocs.js";
6
+ export * from "./adoptionPlan.js";
7
+ export * from "./template.js";
8
+ export * from "./dogfood.js";
9
+ export * from "./recommendConfig.js";
@@ -0,0 +1,9 @@
1
+ export * from "./indexWorkspace.js";
2
+ export * from "./validate.js";
3
+ export * from "./check.js";
4
+ export * from "./schema.js";
5
+ export * from "./auditDocs.js";
6
+ export * from "./adoptionPlan.js";
7
+ export * from "./template.js";
8
+ export * from "./dogfood.js";
9
+ export * from "./recommendConfig.js";
@@ -0,0 +1,8 @@
1
+ export interface IndexCommandOptions {
2
+ workspace: string;
3
+ config?: string;
4
+ mode?: "committed" | "local" | "memory";
5
+ write?: boolean;
6
+ pretty?: boolean;
7
+ }
8
+ export declare function runIndexCommand(options: IndexCommandOptions): Record<string, unknown>;
@@ -0,0 +1,23 @@
1
+ import path from "node:path";
2
+ import { indexWorkspace } from "../../catalogue/indexer.js";
3
+ export function runIndexCommand(options) {
4
+ const workspaceRoot = path.resolve(options.workspace);
5
+ const { snapshot } = indexWorkspace({
6
+ workspaceRoot,
7
+ configPath: options.config,
8
+ mode: options.mode,
9
+ write: options.write,
10
+ pretty: options.pretty
11
+ });
12
+ return {
13
+ ok: true,
14
+ data: {
15
+ catalogueId: snapshot.catalogueId,
16
+ stats: snapshot.stats
17
+ },
18
+ warnings: [],
19
+ provenance: {
20
+ source: "cli:index"
21
+ }
22
+ };
23
+ }
@@ -0,0 +1,7 @@
1
+ export interface RecommendConfigCommandOptions {
2
+ workspace: string;
3
+ config?: string;
4
+ mode?: "committed" | "local" | "memory";
5
+ limit?: number;
6
+ }
7
+ export declare function runRecommendConfigCommand(options: RecommendConfigCommandOptions): Record<string, unknown>;
@@ -0,0 +1,20 @@
1
+ import path from "node:path";
2
+ import { indexWorkspace } from "../../catalogue/indexer.js";
3
+ import { recommendConfig } from "../../queries/recommendConfig.js";
4
+ export function runRecommendConfigCommand(options) {
5
+ const workspaceRoot = path.resolve(options.workspace);
6
+ const { snapshot } = indexWorkspace({
7
+ workspaceRoot,
8
+ configPath: options.config,
9
+ mode: options.mode ?? "memory",
10
+ write: false
11
+ });
12
+ return {
13
+ ok: true,
14
+ data: recommendConfig(snapshot, { limit: options.limit }),
15
+ warnings: [],
16
+ provenance: {
17
+ source: "mapwright"
18
+ }
19
+ };
20
+ }
@@ -0,0 +1 @@
1
+ export declare function runSchemaCommand(): Record<string, unknown>;
@@ -0,0 +1,37 @@
1
+ import { CURRENT_SCHEMA_VERSION, SUPPORTED_SCHEMA_VERSIONS, SUPPORTED_IDENTITY_SCHEMES } from "../../catalogue/store.js";
2
+ import { IDENTITY_SCHEME } from "../../catalogue/identity.js";
3
+ export function runSchemaCommand() {
4
+ return {
5
+ ok: true,
6
+ data: {
7
+ schemaVersion: CURRENT_SCHEMA_VERSION,
8
+ supportedSchemaVersions: [...SUPPORTED_SCHEMA_VERSIONS],
9
+ identityScheme: IDENTITY_SCHEME,
10
+ supportedIdentitySchemes: [...SUPPORTED_IDENTITY_SCHEMES],
11
+ snapshot: {
12
+ required: [
13
+ "schemaVersion",
14
+ "identityScheme",
15
+ "catalogueId",
16
+ "generator",
17
+ "mode",
18
+ "stats",
19
+ "files",
20
+ "packages",
21
+ "capabilities",
22
+ "publicApis",
23
+ "examples",
24
+ "symbols",
25
+ "relationships",
26
+ "tests",
27
+ "diagnostics",
28
+ "provenance"
29
+ ]
30
+ }
31
+ },
32
+ warnings: [],
33
+ provenance: {
34
+ source: "cli:schema"
35
+ }
36
+ };
37
+ }
@@ -0,0 +1,5 @@
1
+ export interface TemplateCommandOptions {
2
+ templateId?: string;
3
+ list?: boolean;
4
+ }
5
+ export declare function runTemplateCommand(options: TemplateCommandOptions): Record<string, unknown>;
@@ -0,0 +1,44 @@
1
+ import { getDocumentationTemplate, listDocumentationTemplateIds, listDocumentationTemplates } from "../../catalogue/templates.js";
2
+ export function runTemplateCommand(options) {
3
+ if (options.list) {
4
+ return {
5
+ ok: true,
6
+ data: {
7
+ templates: listDocumentationTemplates()
8
+ },
9
+ warnings: [],
10
+ provenance: {
11
+ source: "mapwright"
12
+ }
13
+ };
14
+ }
15
+ const templateId = options.templateId ?? "";
16
+ if (!isDocumentationTemplateId(templateId)) {
17
+ return {
18
+ ok: false,
19
+ error: {
20
+ code: "template_not_found",
21
+ message: `Unknown template ${templateId}.`
22
+ },
23
+ warnings: [],
24
+ data: {
25
+ availableTemplateIds: listDocumentationTemplateIds(),
26
+ templates: listDocumentationTemplates()
27
+ },
28
+ provenance: {
29
+ source: "mapwright"
30
+ }
31
+ };
32
+ }
33
+ return {
34
+ ok: true,
35
+ data: getDocumentationTemplate(templateId),
36
+ warnings: [],
37
+ provenance: {
38
+ source: "mapwright"
39
+ }
40
+ };
41
+ }
42
+ function isDocumentationTemplateId(value) {
43
+ return listDocumentationTemplateIds().includes(value);
44
+ }
@@ -0,0 +1,9 @@
1
+ export interface ValidateCommandOptions {
2
+ workspace: string;
3
+ config?: string;
4
+ failOn?: "info" | "warning" | "error" | "never";
5
+ }
6
+ export declare function runValidateCommand(options: ValidateCommandOptions): {
7
+ output: Record<string, unknown>;
8
+ exitCode: number;
9
+ };
@@ -0,0 +1,85 @@
1
+ import path from "node:path";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { indexWorkspace, shouldFailFromDiagnostics, staleCommittedCatalogue } from "../../catalogue/indexer.js";
4
+ import { loadConfig } from "../../catalogue/config.js";
5
+ import { OUTPUT_FILES } from "../../catalogue/store.js";
6
+ export function runValidateCommand(options) {
7
+ const workspaceRoot = path.resolve(options.workspace);
8
+ const { config } = loadConfig({ workspaceRoot, configPath: options.config });
9
+ const { snapshot } = indexWorkspace({ workspaceRoot, configPath: options.config, mode: "committed", write: false });
10
+ let state = "catalogue_current";
11
+ const diagnostics = [...snapshot.diagnostics];
12
+ const committedPath = path.resolve(workspaceRoot, config.catalogueDir, OUTPUT_FILES.catalogue);
13
+ if (config.committedCatalogue) {
14
+ if (!existsSync(committedPath)) {
15
+ state = "catalogue_missing";
16
+ diagnostics.push({
17
+ id: "diag:catalogue_missing",
18
+ severity: "error",
19
+ category: "determinism",
20
+ code: "catalogue_missing",
21
+ message: "Committed catalogue file is missing.",
22
+ provenance: { source: "validate" }
23
+ });
24
+ }
25
+ else {
26
+ try {
27
+ JSON.parse(readFileSync(committedPath, "utf8"));
28
+ const stale = staleCommittedCatalogue(workspaceRoot, snapshot, config.catalogueDir);
29
+ if (stale) {
30
+ state = "catalogue_stale";
31
+ diagnostics.push({
32
+ id: "diag:catalogue_stale",
33
+ severity: "error",
34
+ category: "determinism",
35
+ code: "catalogue_stale",
36
+ message: "Committed catalogue is stale compared with indexed snapshot.",
37
+ provenance: { source: "validate" }
38
+ });
39
+ }
40
+ }
41
+ catch {
42
+ state = "catalogue_unreadable";
43
+ diagnostics.push({
44
+ id: "diag:catalogue_unreadable",
45
+ severity: "error",
46
+ category: "determinism",
47
+ code: "catalogue_unreadable",
48
+ message: "Committed catalogue exists but cannot be parsed.",
49
+ provenance: { source: "validate" }
50
+ });
51
+ }
52
+ }
53
+ }
54
+ const failOn = options.failOn ?? config.validation.failOn;
55
+ const diagnosticsFailedThreshold = shouldFailFromDiagnostics(failOn, diagnostics);
56
+ const structuralFailure = config.committedCatalogue && state !== "catalogue_current";
57
+ const failed = structuralFailure || diagnosticsFailedThreshold;
58
+ if (diagnosticsFailedThreshold) {
59
+ diagnostics.push({
60
+ id: "diag:diagnostics_failed_threshold",
61
+ severity: "error",
62
+ category: "determinism",
63
+ code: "diagnostics_failed_threshold",
64
+ message: `Diagnostics met or exceeded configured fail threshold ${failOn}.`,
65
+ provenance: { source: "validate" }
66
+ });
67
+ }
68
+ diagnostics.sort((a, b) => a.id.localeCompare(b.id));
69
+ return {
70
+ output: {
71
+ ok: !failed,
72
+ data: {
73
+ state,
74
+ diagnostics,
75
+ failOn,
76
+ diagnosticsFailedThreshold
77
+ },
78
+ warnings: [],
79
+ provenance: {
80
+ source: "cli:validate"
81
+ }
82
+ },
83
+ exitCode: failed ? 1 : 0
84
+ };
85
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};