@nimiplatform/nimi-coding 0.3.1 → 0.5.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 (115) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/CONTRIBUTING.md +3 -3
  3. package/README.md +297 -41
  4. package/README.zh-CN.md +306 -31
  5. package/bin/nimicoding.mjs +1 -1
  6. package/cli/commands/authority.mjs +804 -0
  7. package/cli/commands/clear.mjs +27 -7
  8. package/cli/commands/doctor.mjs +10 -1
  9. package/cli/commands/start.mjs +23 -27
  10. package/cli/commands/sync.mjs +21 -101
  11. package/cli/constants.mjs +7 -31
  12. package/cli/dev/check-authority-surface.mjs +182 -0
  13. package/cli/dev/check-product-conformance.mjs +889 -0
  14. package/cli/help.mjs +10 -17
  15. package/cli/index.mjs +6 -47
  16. package/cli/lib/authority/anchors.mjs +491 -0
  17. package/cli/lib/authority/audit.mjs +567 -0
  18. package/cli/lib/authority/change-candidates.mjs +807 -0
  19. package/cli/lib/authority/closed-sets.mjs +645 -0
  20. package/cli/lib/authority/compile.mjs +92 -0
  21. package/cli/lib/authority/compiled-snapshot.mjs +143 -0
  22. package/cli/lib/authority/consumers.mjs +520 -0
  23. package/cli/lib/authority/diagnostics.mjs +93 -0
  24. package/cli/lib/authority/diff.mjs +310 -0
  25. package/cli/lib/authority/discover.mjs +447 -0
  26. package/cli/lib/authority/format.mjs +169 -0
  27. package/cli/lib/authority/git-snapshot.mjs +720 -0
  28. package/cli/lib/authority/graph.mjs +351 -0
  29. package/cli/lib/authority/impact.mjs +125 -0
  30. package/cli/lib/authority/lexicon.mjs +55 -0
  31. package/cli/lib/authority/query.mjs +162 -0
  32. package/cli/lib/authority/repository-corpus.mjs +37 -0
  33. package/cli/lib/authority/repository-inventory.mjs +34 -0
  34. package/cli/lib/authority/review.mjs +212 -0
  35. package/cli/lib/authority/sarif.mjs +174 -0
  36. package/cli/lib/authority/scope-bindings.mjs +225 -0
  37. package/cli/lib/authority/source-map.mjs +105 -0
  38. package/cli/lib/authority/source-markdown.mjs +167 -0
  39. package/cli/lib/authority/source-yaml.mjs +308 -0
  40. package/cli/lib/authority/surface.mjs +97 -0
  41. package/cli/lib/authority/terms.mjs +422 -0
  42. package/cli/lib/authority/tracked-text.mjs +70 -0
  43. package/cli/lib/authority/validate.mjs +300 -0
  44. package/cli/lib/bootstrap.mjs +55 -71
  45. package/cli/lib/doctor.mjs +40 -123
  46. package/cli/lib/entrypoints.mjs +104 -105
  47. package/cli/lib/fs-helpers.mjs +139 -15
  48. package/cli/lib/internal/governance/config.mjs +0 -36
  49. package/cli/lib/shared.mjs +8 -21
  50. package/cli/lib/sync.mjs +81 -92
  51. package/cli/lib/value-helpers.mjs +0 -26
  52. package/cli/lib/yaml-helpers.mjs +1 -124
  53. package/cli/seeds/bootstrap.mjs +31 -87
  54. package/cli/seeds/seed-policy.yaml +9 -63
  55. package/contracts/authority-scope-bindings.schema.yaml +15 -0
  56. package/contracts/authority-source.schema.yaml +58 -0
  57. package/contracts/authority-verifier-bindings.schema.yaml +31 -0
  58. package/methodology/authority-authoring.yaml +127 -0
  59. package/methodology/core.yaml +34 -27
  60. package/package.json +10 -6
  61. package/spec/authority-anchors.yaml +99 -0
  62. package/spec/authority-audit.yaml +89 -0
  63. package/spec/authority-authoring.yaml +137 -0
  64. package/spec/authority-change-candidates.yaml +146 -0
  65. package/spec/authority-closed-sets.yaml +65 -0
  66. package/spec/authority-consumers.yaml +77 -0
  67. package/spec/authority-context.yaml +50 -0
  68. package/spec/authority-discovery.yaml +119 -0
  69. package/spec/authority-graph.yaml +59 -0
  70. package/spec/authority-impact.yaml +61 -0
  71. package/spec/authority-review.yaml +71 -0
  72. package/spec/authority-terms.yaml +63 -0
  73. package/spec/product-scope.yaml +37 -23
  74. package/cli/commands/blueprint-audit.mjs +0 -91
  75. package/cli/commands/classify-spec-tree.mjs +0 -5
  76. package/cli/commands/generate-spec-derived-docs.mjs +0 -151
  77. package/cli/commands/generate-spec-migration-plan.mjs +0 -30
  78. package/cli/commands/surface-validator-command.mjs +0 -49
  79. package/cli/commands/validate-domain-admission.mjs +0 -5
  80. package/cli/commands/validate-guidance-bodies.mjs +0 -5
  81. package/cli/commands/validate-placement.mjs +0 -5
  82. package/cli/commands/validate-projection-edges.mjs +0 -5
  83. package/cli/commands/validate-spec-audit.mjs +0 -27
  84. package/cli/commands/validate-spec-governance.mjs +0 -144
  85. package/cli/commands/validate-spec-tree.mjs +0 -27
  86. package/cli/commands/validate-table-family.mjs +0 -5
  87. package/cli/commands/validate-tracked-output-admission.mjs +0 -5
  88. package/cli/lib/blueprint-audit.mjs +0 -363
  89. package/cli/lib/contracts.mjs +0 -21
  90. package/cli/lib/internal/contracts-loaders.mjs +0 -47
  91. package/cli/lib/internal/contracts-parse.mjs +0 -192
  92. package/cli/lib/internal/governance/runner.mjs +0 -35
  93. package/cli/lib/internal/surface-taxonomy-validators.mjs +0 -1147
  94. package/cli/lib/internal/validators-shared.mjs +0 -12
  95. package/cli/lib/internal/validators-spec-helpers.mjs +0 -52
  96. package/cli/lib/internal/validators-spec.mjs +0 -380
  97. package/cli/lib/validators.mjs +0 -30
  98. package/config/bootstrap.yaml +0 -6
  99. package/config/spec-generation-inputs.yaml +0 -41
  100. package/contracts/domain-admission.schema.yaml +0 -56
  101. package/contracts/migration-inventory.schema.yaml +0 -15
  102. package/contracts/negative-fixtures.yaml +0 -26
  103. package/contracts/placement-contract.schema.yaml +0 -127
  104. package/contracts/projection-edge.schema.yaml +0 -46
  105. package/contracts/shared-enums.yaml +0 -63
  106. package/contracts/spec-generation-audit.schema.yaml +0 -46
  107. package/contracts/spec-generation-inputs.schema.yaml +0 -43
  108. package/contracts/spec-layout.schema.yaml +0 -32
  109. package/contracts/surface-taxonomy.schema.yaml +0 -139
  110. package/contracts/table-family.schema.yaml +0 -133
  111. package/contracts/tracked-output-admission.schema.yaml +0 -17
  112. package/methodology/four-closure-policy.yaml +0 -20
  113. package/methodology/role-separation-policy.yaml +0 -22
  114. package/methodology/spec-reconstruction.yaml +0 -69
  115. package/spec/_meta/spec-tree-model.yaml +0 -44
@@ -0,0 +1,92 @@
1
+ import { compareText } from "./diagnostics.mjs";
2
+ import { formattingDiagnostics, parseAuthorityPath } from "./format.mjs";
3
+ import { validateAuthorityScopeBindings } from "./scope-bindings.mjs";
4
+ import { buildSourceMap } from "./source-map.mjs";
5
+ import { validateAuthoritySources } from "./validate.mjs";
6
+
7
+ function lowerUnit(source) {
8
+ const data = source.data;
9
+ const unit = {
10
+ id: data.id,
11
+ kind: data.kind,
12
+ owner: data.owner,
13
+ lifecycle: data.lifecycle,
14
+ metadata: {
15
+ title: data.title,
16
+ ...(data.reason === undefined ? {} : { reason: data.reason }),
17
+ },
18
+ relations: [...data.relations]
19
+ .map((relation) => ({ type: relation.type, target: relation.target }))
20
+ .sort((left, right) => compareText(left.type, right.type) || compareText(left.target, right.target)),
21
+ };
22
+ if (data.lifecycle === "active" && data.kind === "definition") unit.semantic = { meaning: data.meaning };
23
+ if (data.lifecycle === "active" && data.kind === "rule") unit.semantic = {
24
+ modality: data.modality,
25
+ scope: [...data.scope].sort(compareText),
26
+ statement: data.statement,
27
+ condition: data.condition,
28
+ failure: data.failure,
29
+ };
30
+ return unit;
31
+ }
32
+
33
+ async function admittedSources(inputPath) {
34
+ const parsed = await parseAuthorityPath(inputPath);
35
+ const formatDiagnostics = formattingDiagnostics(parsed.documents, parsed.contract);
36
+ if (formatDiagnostics.length > 0) return { ok: false, diagnostics: formatDiagnostics, parsed };
37
+ const validation = validateAuthoritySources(parsed.sources, parsed.contract);
38
+ if (!validation.ok) return { ok: false, diagnostics: validation.diagnostics, parsed };
39
+ return { ok: true, diagnostics: [], parsed };
40
+ }
41
+
42
+ export async function checkAuthorityPath(inputPath, { scopeBindings = null } = {}) {
43
+ const result = await admittedSources(inputPath);
44
+ if (!result.ok || scopeBindings === null) return {
45
+ ok: result.ok,
46
+ diagnostics: result.diagnostics,
47
+ fileCount: result.parsed.files.length,
48
+ unitCount: result.ok ? result.parsed.sources.length : 0,
49
+ };
50
+ const scopeValidation = await validateAuthorityScopeBindings(result.parsed.sources, scopeBindings);
51
+ return {
52
+ ok: scopeValidation.ok,
53
+ diagnostics: scopeValidation.diagnostics,
54
+ fileCount: result.parsed.files.length,
55
+ unitCount: scopeValidation.ok ? result.parsed.sources.length : 0,
56
+ };
57
+ }
58
+
59
+ export async function compileAuthorityPath(inputPath) {
60
+ const admitted = await admittedSources(inputPath);
61
+ const inputBytes = admitted.parsed.documents.reduce((total, document) => total + document.inputBytes, 0);
62
+ if (!admitted.ok) return {
63
+ ok: false,
64
+ diagnostics: admitted.diagnostics,
65
+ fileCount: admitted.parsed.files.length,
66
+ unitCount: 0,
67
+ inputBytes,
68
+ ir: null,
69
+ sourceMap: null,
70
+ };
71
+ const sources = [...admitted.parsed.sources].sort((left, right) => compareText(left.data.id, right.data.id));
72
+ const ir = { units: sources.map(lowerUnit) };
73
+ const mapped = buildSourceMap(sources, ir);
74
+ if (!mapped.ok) return {
75
+ ok: false,
76
+ diagnostics: mapped.diagnostics,
77
+ fileCount: admitted.parsed.files.length,
78
+ unitCount: 0,
79
+ inputBytes,
80
+ ir: null,
81
+ sourceMap: null,
82
+ };
83
+ return {
84
+ ok: true,
85
+ diagnostics: [],
86
+ fileCount: admitted.parsed.files.length,
87
+ unitCount: ir.units.length,
88
+ inputBytes,
89
+ ir,
90
+ sourceMap: mapped.sourceMap,
91
+ };
92
+ }
@@ -0,0 +1,143 @@
1
+ import path from "node:path";
2
+
3
+ import { compareText, portablePath } from "./diagnostics.mjs";
4
+
5
+ class ReadonlyIndex {
6
+ #values;
7
+
8
+ constructor(entries) {
9
+ this.#values = new Map(entries);
10
+ Object.freeze(this);
11
+ }
12
+
13
+ get size() {
14
+ return this.#values.size;
15
+ }
16
+
17
+ get(key) {
18
+ return this.#values.get(key);
19
+ }
20
+
21
+ has(key) {
22
+ return this.#values.has(key);
23
+ }
24
+
25
+ *entries() {
26
+ for (const [key, value] of this.#values) yield Object.freeze([key, value]);
27
+ }
28
+
29
+ keys() {
30
+ return this.#values.keys();
31
+ }
32
+
33
+ values() {
34
+ return this.#values.values();
35
+ }
36
+
37
+ forEach(callback, thisArg = undefined) {
38
+ for (const [key, value] of this.#values) callback.call(thisArg, value, key, this);
39
+ }
40
+
41
+ [Symbol.iterator]() {
42
+ return this.entries();
43
+ }
44
+
45
+ get [Symbol.toStringTag]() {
46
+ return "ReadonlyIndex";
47
+ }
48
+ }
49
+
50
+ function freezeTree(value, seen = new Set()) {
51
+ if (value === null || typeof value !== "object" || Object.isFrozen(value) || seen.has(value)) return value;
52
+ seen.add(value);
53
+ for (const key of Reflect.ownKeys(value)) freezeTree(value[key], seen);
54
+ return Object.freeze(value);
55
+ }
56
+
57
+ function readonlyIndex(entries) {
58
+ return new ReadonlyIndex([...entries].sort(([left], [right]) => compareText(left, right)));
59
+ }
60
+
61
+ function groupedIndex(entries, keys) {
62
+ const groups = new Map();
63
+ for (const entry of entries) {
64
+ for (const key of keys(entry)) {
65
+ const values = groups.get(key) ?? [];
66
+ values.push(entry);
67
+ groups.set(key, values);
68
+ }
69
+ }
70
+ return readonlyIndex([...groups.entries()].map(([key, values]) => [
71
+ key,
72
+ Object.freeze(values.sort((left, right) => compareText(left.unit.id, right.unit.id))),
73
+ ]));
74
+ }
75
+
76
+ function compareEdge(left, right) {
77
+ return compareText(left.source, right.source)
78
+ || compareText(left.type, right.type)
79
+ || compareText(left.target, right.target);
80
+ }
81
+
82
+ function adjacencyIndexes(entries) {
83
+ const outgoing = new Map(entries.map((entry) => [entry.unit.id, []]));
84
+ const incoming = new Map(entries.map((entry) => [entry.unit.id, []]));
85
+ for (const entry of entries) {
86
+ entry.unit.relations.forEach((relation, relationIndex) => {
87
+ const edge = Object.freeze({
88
+ source: entry.unit.id,
89
+ type: relation.type,
90
+ target: relation.target,
91
+ sourceUnitIndex: entry.unitIndex,
92
+ relationIndex,
93
+ });
94
+ outgoing.get(edge.source).push(edge);
95
+ incoming.get(edge.target).push(edge);
96
+ });
97
+ }
98
+ const finish = (index) => readonlyIndex([...index.entries()].map(([id, edges]) => [
99
+ id,
100
+ Object.freeze(edges.sort(compareEdge)),
101
+ ]));
102
+ return { outgoing: finish(outgoing), incoming: finish(incoming) };
103
+ }
104
+
105
+ export function createCompiledAuthoritySnapshot(compiled, inputRoot) {
106
+ if (
107
+ compiled?.ok !== true
108
+ || !Array.isArray(compiled?.ir?.units)
109
+ || compiled?.sourceMap?.fields === null
110
+ || typeof compiled?.sourceMap?.fields !== "object"
111
+ ) {
112
+ throw new TypeError("compiled authority snapshot requires one successful compiler result");
113
+ }
114
+ if (typeof inputRoot !== "string" || inputRoot.length === 0) {
115
+ throw new TypeError("compiled authority snapshot requires one non-empty input root");
116
+ }
117
+ const resolvedRoot = path.resolve(inputRoot);
118
+ const entries = compiled.ir.units.map((unit, unitIndex) => {
119
+ const mapped = compiled.sourceMap.fields[`/units/${unitIndex}/id`];
120
+ if (!mapped) throw new TypeError(`compiled authority snapshot cannot locate unit identity: ${unit.id}`);
121
+ return Object.freeze({
122
+ unit,
123
+ unitIndex,
124
+ container: portablePath(mapped.file, resolvedRoot),
125
+ });
126
+ });
127
+ const byId = readonlyIndex(entries.map((entry) => [entry.unit.id, entry]));
128
+ const byOwner = groupedIndex(entries, (entry) => [entry.unit.owner]);
129
+ const byScope = groupedIndex(entries, (entry) => entry.unit.semantic?.scope ?? []);
130
+ const byContainer = groupedIndex(entries, (entry) => [entry.container]);
131
+ const { incoming, outgoing } = adjacencyIndexes(entries);
132
+ freezeTree(compiled);
133
+ return Object.freeze({
134
+ inputRoot: resolvedRoot,
135
+ compiled,
136
+ byId,
137
+ byOwner,
138
+ byScope,
139
+ byContainer,
140
+ incoming,
141
+ outgoing,
142
+ });
143
+ }