@ecoma-io/archkeep 0.24.0 → 0.25.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 (79) hide show
  1. package/package.json +1 -1
  2. package/src/analysis/csharp.mjs +3 -1
  3. package/src/analysis/dotnet/csproj.mjs +5 -1
  4. package/src/analysis/dotnet/namespaces.mjs +1 -0
  5. package/src/analysis/go.mjs +6 -0
  6. package/src/analysis/java.mjs +2 -0
  7. package/src/analysis/jvm/gradle.mjs +3 -1
  8. package/src/analysis/jvm/maven.mjs +6 -1
  9. package/src/analysis/jvm/packages.mjs +1 -0
  10. package/src/analysis/jvm/resolve.mjs +4 -2
  11. package/src/analysis/kotlin.mjs +2 -0
  12. package/src/analysis/markdown.mjs +1 -0
  13. package/src/analysis/python.mjs +8 -0
  14. package/src/analysis/rust.mjs +5 -1
  15. package/src/analysis/source-util.mjs +1 -1
  16. package/src/analysis/typescript.mjs +2 -0
  17. package/src/architecture-intent/model.mjs +11 -7
  18. package/src/architecture-intent/selectors.mjs +2 -1
  19. package/src/commands/change-intent.mjs +10 -9
  20. package/src/commands/change.mjs +86 -23
  21. package/src/commands/check.mjs +11 -9
  22. package/src/commands/completeness.mjs +7 -6
  23. package/src/commands/coverage-acceptance.mjs +46 -0
  24. package/src/commands/custom-rules.mjs +1 -0
  25. package/src/commands/delta-classify.mjs +3 -0
  26. package/src/commands/delta-snapshot.mjs +27 -5
  27. package/src/commands/delta.mjs +73 -39
  28. package/src/commands/diff.mjs +3 -9
  29. package/src/commands/drift.mjs +1 -1
  30. package/src/commands/evaluation-primitives.mjs +4 -4
  31. package/src/commands/evolution.mjs +2 -0
  32. package/src/commands/explain.mjs +2 -0
  33. package/src/commands/graph.mjs +39 -17
  34. package/src/commands/history.mjs +36 -0
  35. package/src/commands/plan-context-command.mjs +4 -1
  36. package/src/commands/policy.mjs +5 -2
  37. package/src/commands/scenario-evaluation.mjs +1 -1
  38. package/src/commands/snapshot-meta.mjs +33 -0
  39. package/src/commands/trajectory.mjs +2 -1
  40. package/src/config.mjs +1 -1
  41. package/src/custom-rules/host.mjs +3 -3
  42. package/src/custom-rules/values.mjs +1 -4
  43. package/src/eslint-config.mjs +1 -0
  44. package/src/fixtures/evolution-lifecycle/workspace.mjs +15 -4
  45. package/src/go-work.mjs +1 -1
  46. package/src/governance/adr-registry.mjs +4 -1
  47. package/src/governance/debt-ledger.mjs +1 -1
  48. package/src/governance/decision-fitness.mjs +2 -0
  49. package/src/governance/decision-graph.mjs +1 -0
  50. package/src/governance/discovery-proposal.mjs +8 -2
  51. package/src/governance/evolution-event.mjs +42 -0
  52. package/src/governance/fitness-registry.mjs +16 -1
  53. package/src/governance/preset-fingerprints.json +14 -14
  54. package/src/governance/profile-registry.mjs +22 -3
  55. package/src/governance/provenance-record.mjs +4 -1
  56. package/src/governance/reconcile-score.mjs +4 -0
  57. package/src/governance/row-schema.mjs +1 -0
  58. package/src/governance/verdict.mjs +37 -4
  59. package/src/governance/waiver.mjs +1 -0
  60. package/src/intent/intent-manifest.json +18 -12
  61. package/src/intent/mask-non-code.mjs +1 -0
  62. package/src/lsp/diagnostics.mjs +3 -2
  63. package/src/lsp/protocol.mjs +2 -1
  64. package/src/lsp/server.mjs +3 -0
  65. package/src/lsp/workspace-index.mjs +3 -1
  66. package/src/providers/native/differential.fixtures.mjs +29 -11
  67. package/src/providers/native/index.mjs +2 -1
  68. package/src/providers/native/model.mjs +4 -0
  69. package/src/report/envelope-shape.mjs +2 -0
  70. package/src/report/json.mjs +4 -2
  71. package/src/report/sarif.mjs +21 -8
  72. package/src/report/snapshot-text.mjs +3 -3
  73. package/src/report/text.mjs +10 -2
  74. package/src/rules/match.mjs +7 -5
  75. package/src/rules/specifiers.mjs +2 -0
  76. package/src/rules/tags.mjs +3 -2
  77. package/src/rules/topology.mjs +6 -1
  78. package/src/values.mjs +11 -0
  79. package/src/workspace.mjs +1 -0
@@ -29,7 +29,7 @@ import { tagMatches } from "./match.mjs";
29
29
  import { getPath, pathExists } from "./reachability.mjs";
30
30
 
31
31
  /** `"a", "b"` — how upstream renders a tag list inside a message. */
32
- export function stringifyTags(tags) {
32
+ function stringifyTags(tags) {
33
33
  return tags.map((t) => `"${t}"`).join(", ");
34
34
  }
35
35
 
@@ -55,7 +55,7 @@ export function hasTag(project, tag) {
55
55
  }
56
56
 
57
57
  /** True when the project carries NONE of these tags — upstream's spelling. */
58
- export function hasNoneOfTheseTags(project, tags) {
58
+ function hasNoneOfTheseTags(project, tags) {
59
59
  return tags.filter((tag) => hasTag(project, tag)).length === 0;
60
60
  }
61
61
 
@@ -165,6 +165,7 @@ export function orphanedNotDependOnTags(depConstraints, graph) {
165
165
  * are what the message prints so a reader can see the hop that did it.
166
166
  */
167
167
  export function findDependenciesWithTags(targetProject, tags, graph, reach) {
168
+ // used by its own test
168
169
  const reachable = Object.keys(graph.nodes)
169
170
  .sort()
170
171
  .filter(
@@ -57,6 +57,7 @@ export function appIsMFERemote(project) {
57
57
  * — the common case, and the one that keeps `noSelfCircularDependencies` armed.
58
58
  */
59
59
  export function entryPointOf(file, projectRoot, entryPoints) {
60
+ // used by its own test
60
61
  if (!entryPoints || entryPoints.length === 0) return undefined;
61
62
  const fileEntryPoint = entryPoints.find((entry) => entry.file === file);
62
63
  if (fileEntryPoint) return fileEntryPoint.file;
@@ -88,7 +89,7 @@ export function entryPointOf(file, projectRoot, entryPoints) {
88
89
  * standing in for upstream's module resolution — the resolver already ran; this
89
90
  * layer never runs a second one.
90
91
  */
91
- export function secondaryEntryPointPath(resolvedFile, targetProject) {
92
+ function secondaryEntryPointPath(resolvedFile, targetProject) {
92
93
  if (!resolvedFile) return undefined;
93
94
  return entryPointOf(resolvedFile, targetProject.data.root, targetProject.data?.entryPoints);
94
95
  }
@@ -128,6 +129,7 @@ export function belongsToDifferentEntryPoint(resolvedFile, sourceFile, sourcePro
128
129
  * @returns {string[]|null}
129
130
  */
130
131
  export function findDynamicImportPath(graph, sourceProjectName, targetProjectName, visited = []) {
132
+ // used by its own test
131
133
  if (visited.indexOf(sourceProjectName) > -1) return null;
132
134
  for (const dependency of graph.dependencies?.[sourceProjectName] ?? []) {
133
135
  if (dependency.type !== DYNAMIC) continue;
@@ -152,6 +154,7 @@ export function findDynamicImportPath(graph, sourceProjectName, targetProjectNam
152
154
  * fired, and then the verdict would name evidence for a route nobody walked.
153
155
  */
154
156
  export function hasDynamicImport(graph, sourceProjectName, targetProjectName) {
157
+ // used by its own test
155
158
  return findDynamicImportPath(graph, sourceProjectName, targetProjectName) !== null;
156
159
  }
157
160
 
@@ -209,6 +212,7 @@ export function createFileDependencyIndex(edges) {
209
212
 
210
213
  /** The files carrying each hop of a path — one entry per consecutive pair. */
211
214
  export function findFilesInCircularPath(fileIndex, circularPath) {
215
+ // used by its own test
212
216
  const chain = [];
213
217
  for (let i = 0; i < circularPath.length - 1; i++) {
214
218
  chain.push(fileIndex.any.get(edgeKey(circularPath[i].name, circularPath[i + 1].name)) ?? []);
@@ -218,6 +222,7 @@ export function findFilesInCircularPath(fileIndex, circularPath) {
218
222
 
219
223
  /** The files that lazy-load `target` from inside `source`. */
220
224
  export function findFilesWithDynamicImports(fileIndex, sourceProjectName, targetProjectName) {
225
+ // used by its own test
221
226
  return fileIndex.dynamic.get(edgeKey(sourceProjectName, targetProjectName)) ?? [];
222
227
  }
223
228
 
package/src/values.mjs CHANGED
@@ -36,6 +36,17 @@ export const isPlainObject = (value) =>
36
36
  export const isStringArray = (value) =>
37
37
  Array.isArray(value) && value.every((item) => typeof item === "string");
38
38
 
39
+ /**
40
+ * Whether a value is a string a reader could actually act on — non-empty
41
+ * after trimming. The verdict contract's reason fields (I3/I4) refuse
42
+ * everything else: `""` and `" "` are byte-present but semantically
43
+ * absent, and a non-string reason would ship a `typeof` artifact where the
44
+ * reader was promised a sentence.
45
+ *
46
+ * @type {(value: unknown) => value is string}
47
+ */
48
+ export const isNonEmptyString = (value) => typeof value === "string" && value.trim() !== "";
49
+
39
50
  /**
40
51
  * A value's type, for an error message that shows what was actually there.
41
52
  *
package/src/workspace.mjs CHANGED
@@ -721,6 +721,7 @@ const DOTLESS_FURNITURE = Object.freeze(
721
721
  * @returns {boolean}
722
722
  */
723
723
  export function exemptFromUnsupportedLanguage(sourceFile) {
724
+ // used by its own test
724
725
  const base = sourceFile.slice(sourceFile.lastIndexOf("/") + 1);
725
726
  // Dotfiles are editor and tool state (`.gitignore`, `.env`, `.npmrc`).
726
727
  if (base.startsWith(".")) return true;