semantifold 0.8.0 → 0.10.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 (171) hide show
  1. package/README.md +11 -5
  2. package/bin/semantifold.js +6 -0
  3. package/build/bin/semantifold.d.ts +3 -0
  4. package/build/bin/semantifold.d.ts.map +1 -0
  5. package/build/bin/semantifold.js +5 -0
  6. package/build/index.d.ts +9 -0
  7. package/build/index.d.ts.map +1 -1
  8. package/build/index.js +10 -1
  9. package/build/src/artifact-path.d.ts +16 -0
  10. package/build/src/artifact-path.d.ts.map +1 -1
  11. package/build/src/artifact-path.js +29 -3
  12. package/build/src/backends/c-check.d.ts +7 -0
  13. package/build/src/backends/c-check.d.ts.map +1 -0
  14. package/build/src/backends/c-check.js +65 -0
  15. package/build/src/backends/check-plan.d.ts +96 -0
  16. package/build/src/backends/check-plan.d.ts.map +1 -0
  17. package/build/src/backends/check-plan.js +135 -0
  18. package/build/src/backends/cpp-check.d.ts +7 -0
  19. package/build/src/backends/cpp-check.d.ts.map +1 -0
  20. package/build/src/backends/cpp-check.js +59 -0
  21. package/build/src/backends/csharp-check.d.ts +7 -0
  22. package/build/src/backends/csharp-check.d.ts.map +1 -0
  23. package/build/src/backends/csharp-check.js +125 -0
  24. package/build/src/backends/csharp.d.ts +1 -0
  25. package/build/src/backends/csharp.d.ts.map +1 -1
  26. package/build/src/backends/csharp.js +5 -4
  27. package/build/src/backends/dart-check.d.ts +7 -0
  28. package/build/src/backends/dart-check.d.ts.map +1 -0
  29. package/build/src/backends/dart-check.js +103 -0
  30. package/build/src/backends/dart.d.ts +2 -0
  31. package/build/src/backends/dart.d.ts.map +1 -1
  32. package/build/src/backends/dart.js +5 -5
  33. package/build/src/backends/go-check.d.ts +7 -0
  34. package/build/src/backends/go-check.d.ts.map +1 -0
  35. package/build/src/backends/go-check.js +77 -0
  36. package/build/src/backends/go.d.ts +1 -0
  37. package/build/src/backends/go.d.ts.map +1 -1
  38. package/build/src/backends/go.js +3 -3
  39. package/build/src/backends/java-check.d.ts +21 -0
  40. package/build/src/backends/java-check.d.ts.map +1 -0
  41. package/build/src/backends/java-check.js +73 -0
  42. package/build/src/backends/javascript-check.d.ts +7 -0
  43. package/build/src/backends/javascript-check.d.ts.map +1 -0
  44. package/build/src/backends/javascript-check.js +29 -0
  45. package/build/src/backends/kotlin-check.d.ts +7 -0
  46. package/build/src/backends/kotlin-check.d.ts.map +1 -0
  47. package/build/src/backends/kotlin-check.js +31 -0
  48. package/build/src/backends/php-check.d.ts +7 -0
  49. package/build/src/backends/php-check.d.ts.map +1 -0
  50. package/build/src/backends/php-check.js +21 -0
  51. package/build/src/backends/program.d.ts +7 -0
  52. package/build/src/backends/program.d.ts.map +1 -1
  53. package/build/src/backends/program.js +16 -1
  54. package/build/src/backends/python-check.d.ts +7 -0
  55. package/build/src/backends/python-check.d.ts.map +1 -0
  56. package/build/src/backends/python-check.js +28 -0
  57. package/build/src/backends/ruby-check.d.ts +7 -0
  58. package/build/src/backends/ruby-check.d.ts.map +1 -0
  59. package/build/src/backends/ruby-check.js +21 -0
  60. package/build/src/backends/rust-check.d.ts +7 -0
  61. package/build/src/backends/rust-check.d.ts.map +1 -0
  62. package/build/src/backends/rust-check.js +65 -0
  63. package/build/src/backends/swift-check.d.ts +7 -0
  64. package/build/src/backends/swift-check.d.ts.map +1 -0
  65. package/build/src/backends/swift-check.js +77 -0
  66. package/build/src/backends/typescript-check.d.ts +7 -0
  67. package/build/src/backends/typescript-check.d.ts.map +1 -0
  68. package/build/src/backends/typescript-check.js +33 -0
  69. package/build/src/backends/zig-check.d.ts +7 -0
  70. package/build/src/backends/zig-check.d.ts.map +1 -0
  71. package/build/src/backends/zig-check.js +70 -0
  72. package/build/src/diagnostic.d.ts +13 -1
  73. package/build/src/diagnostic.d.ts.map +1 -1
  74. package/build/src/diagnostic.js +14 -2
  75. package/build/src/frontends/program.d.ts +6 -0
  76. package/build/src/frontends/program.d.ts.map +1 -1
  77. package/build/src/frontends/program.js +9 -1
  78. package/build/src/language-registry.d.ts +54 -0
  79. package/build/src/language-registry.d.ts.map +1 -1
  80. package/build/src/language-registry.js +107 -5
  81. package/build/src/project-build.d.ts +172 -0
  82. package/build/src/project-build.d.ts.map +1 -0
  83. package/build/src/project-build.js +320 -0
  84. package/build/src/project-cli.d.ts +40 -0
  85. package/build/src/project-cli.d.ts.map +1 -0
  86. package/build/src/project-cli.js +145 -0
  87. package/build/src/project-manifest.d.ts +148 -0
  88. package/build/src/project-manifest.d.ts.map +1 -0
  89. package/build/src/project-manifest.js +432 -0
  90. package/build/src/project-reporter.d.ts +81 -0
  91. package/build/src/project-reporter.d.ts.map +1 -0
  92. package/build/src/project-reporter.js +293 -0
  93. package/build/src/project-snapshot.d.ts +129 -0
  94. package/build/src/project-snapshot.d.ts.map +1 -0
  95. package/build/src/project-snapshot.js +362 -0
  96. package/build/src/project-watch-reporter.d.ts +125 -0
  97. package/build/src/project-watch-reporter.d.ts.map +1 -0
  98. package/build/src/project-watch-reporter.js +280 -0
  99. package/build/src/project-watch.d.ts +133 -0
  100. package/build/src/project-watch.d.ts.map +1 -0
  101. package/build/src/project-watch.js +839 -0
  102. package/build/src/publication.d.ts +218 -0
  103. package/build/src/publication.d.ts.map +1 -0
  104. package/build/src/publication.js +1832 -0
  105. package/build/src/semantic/types.d.ts +613 -0
  106. package/build/src/semantic/types.d.ts.map +1 -1
  107. package/build/src/semantic/types.js +163 -1
  108. package/build/src/subprocess.d.ts +8 -0
  109. package/build/src/subprocess.d.ts.map +1 -1
  110. package/build/src/subprocess.js +50 -9
  111. package/build/src/target-check.d.ts +52 -0
  112. package/build/src/target-check.d.ts.map +1 -0
  113. package/build/src/target-check.js +796 -0
  114. package/build/src/toolchains.d.ts.map +1 -1
  115. package/build/src/toolchains.js +3 -3
  116. package/docs/architecture.md +3 -1
  117. package/docs/c.md +4 -0
  118. package/docs/cpp.md +4 -0
  119. package/docs/dart.md +4 -0
  120. package/docs/generated-artifact-publication.md +98 -0
  121. package/docs/kotlin.md +2 -2
  122. package/docs/language-support.md +29 -3
  123. package/docs/project-build-cli.md +147 -0
  124. package/docs/project-watch.md +60 -0
  125. package/docs/rust.md +4 -0
  126. package/docs/swift.md +2 -0
  127. package/docs/testing.md +70 -3
  128. package/docs/watch-build-pipeline.md +42 -26
  129. package/docs/zig.md +2 -0
  130. package/examples/jsdoc-java-watch/expected-output.txt +3 -0
  131. package/examples/jsdoc-java-watch/semantifold.json +23 -0
  132. package/examples/jsdoc-java-watch/src/main.js +21 -0
  133. package/index.js +9 -0
  134. package/package.json +6 -1
  135. package/src/artifact-path.js +31 -2
  136. package/src/backends/c-check.js +80 -0
  137. package/src/backends/check-plan.js +147 -0
  138. package/src/backends/cpp-check.js +73 -0
  139. package/src/backends/csharp-check.js +139 -0
  140. package/src/backends/csharp.js +4 -3
  141. package/src/backends/dart-check.js +117 -0
  142. package/src/backends/dart.js +4 -4
  143. package/src/backends/go-check.js +89 -0
  144. package/src/backends/go.js +2 -2
  145. package/src/backends/java-check.js +77 -0
  146. package/src/backends/javascript-check.js +33 -0
  147. package/src/backends/kotlin-check.js +41 -0
  148. package/src/backends/php-check.js +23 -0
  149. package/src/backends/program.js +17 -0
  150. package/src/backends/python-check.js +30 -0
  151. package/src/backends/ruby-check.js +23 -0
  152. package/src/backends/rust-check.js +78 -0
  153. package/src/backends/swift-check.js +89 -0
  154. package/src/backends/typescript-check.js +37 -0
  155. package/src/backends/zig-check.js +81 -0
  156. package/src/diagnostic.js +9 -1
  157. package/src/frontends/program.js +9 -0
  158. package/src/language-registry.js +113 -4
  159. package/src/project-build.js +353 -0
  160. package/src/project-cli.js +155 -0
  161. package/src/project-manifest.js +479 -0
  162. package/src/project-reporter.js +320 -0
  163. package/src/project-snapshot.js +403 -0
  164. package/src/project-watch-reporter.js +303 -0
  165. package/src/project-watch.js +870 -0
  166. package/src/publication.js +2071 -0
  167. package/src/semantic/types.js +184 -0
  168. package/src/subprocess.js +49 -8
  169. package/src/target-check.js +844 -0
  170. package/src/toolchains.js +3 -2
  171. package/tsconfig.json +1 -1
@@ -0,0 +1,89 @@
1
+ // @ts-check
2
+
3
+ import path from "node:path"
4
+ import {SemantifoldDiagnostic} from "../diagnostic.js"
5
+ import {
6
+ checkArtifacts,
7
+ checkOutput,
8
+ checkPlan,
9
+ checkStage,
10
+ checkTool,
11
+ environmentPath,
12
+ pathArgument
13
+ } from "./check-plan.js"
14
+
15
+ /**
16
+ * Constructs Swift's warnings-as-errors type-check/compile plan.
17
+ * @param {import("../language-registry.js").TargetCheckPlanContext} context - Validated candidate context.
18
+ * @returns {import("../semantic/types.js").TargetCheckPlan} Immutable Swift plan.
19
+ */
20
+ export function createSwiftCheckPlan(context) {
21
+ const tool = checkTool(context, "swiftc", "swift")
22
+ const artifacts = checkArtifacts(context, artifact => artifact.path.endsWith(".swift"), "swift", "only staged '.swift' sources")
23
+
24
+ if (artifacts.length != 1 || artifacts[0] != path.join(context.sourcePath, "program.swift")) {
25
+ throw new SemantifoldDiagnostic({code: "INVALID_TARGET_CHECK_PLAN", language: "swift",
26
+ message: "Swift developer checks require the exact producer-owned 'program.swift' source."})
27
+ }
28
+ const home = path.join(context.buildPath, "home")
29
+ const cache = path.join(context.buildPath, "cache")
30
+ const temporary = path.join(context.buildPath, "tmp")
31
+ const environment = {
32
+ HOME: home,
33
+ PATH: [path.dirname(tool.executable), "/usr/bin", "/usr/local/bin", "/bin"].filter((value, index, values) =>
34
+ values.indexOf(value) == index).join(path.delimiter),
35
+ TMPDIR: temporary,
36
+ XDG_CACHE_HOME: cache
37
+ }
38
+ const environmentPaths = [environmentPath("HOME", "build"), environmentPath("TMPDIR", "build"),
39
+ environmentPath("XDG_CACHE_HOME", "build")]
40
+ const objects = path.join(context.buildPath, "objects")
41
+ const object = path.join(objects, "program.o")
42
+ const binary = path.join(context.buildPath, "semantifold-swift")
43
+ const typecheckArgv = [
44
+ "--driver-mode=swiftc", "-warnings-as-errors", "-typecheck", "-module-name", "SemantifoldGenerated", ...artifacts
45
+ ]
46
+ const compileArgv = [
47
+ "--driver-mode=swiftc", "-warnings-as-errors", "-c", ...artifacts,
48
+ "-module-name", "SemantifoldGenerated", "-o", "program.o"
49
+ ]
50
+ const linkArgv = ["--driver-mode=swiftc", object, "-Xlinker", "--build-id=none", "-o", binary]
51
+
52
+ return checkPlan(context, "swift", artifacts, [
53
+ checkStage({
54
+ argv: typecheckArgv,
55
+ cwd: context.sourcePath,
56
+ environment,
57
+ environmentPaths,
58
+ inputs: artifacts,
59
+ output: null,
60
+ pathArguments: artifacts.map((_, index) => pathArgument(index + 5, "source")),
61
+ stage: "compile",
62
+ tool
63
+ }),
64
+ checkStage({
65
+ argv: compileArgv,
66
+ cwd: objects,
67
+ environment,
68
+ environmentPaths,
69
+ inputs: artifacts,
70
+ output: null,
71
+ pathArguments: artifacts.map((_, index) => pathArgument(index + 3, "source")),
72
+ stage: "compile",
73
+ tool,
74
+ transientPaths: [objects]
75
+ }),
76
+ checkStage({
77
+ argv: linkArgv,
78
+ cwd: context.buildPath,
79
+ environment,
80
+ environmentPaths,
81
+ inputs: [object],
82
+ output: checkOutput(context.buildPath, "application/x-executable", "compiler-output"),
83
+ pathArguments: [pathArgument(1, "build"), pathArgument(linkArgv.length - 1, "build")],
84
+ stage: "compile",
85
+ tool,
86
+ transientPaths: [objects]
87
+ })
88
+ ])
89
+ }
@@ -0,0 +1,37 @@
1
+ // @ts-check
2
+
3
+ import path from "node:path"
4
+ import {SemantifoldDiagnostic} from "../diagnostic.js"
5
+ import {checkArtifacts, checkPlan, checkStage, checkTool, pathArgument} from "./check-plan.js"
6
+
7
+ /**
8
+ * Constructs TypeScript's non-emitting compiler plan.
9
+ * @param {import("../language-registry.js").TargetCheckPlanContext} context - Validated candidate context.
10
+ * @returns {import("../semantic/types.js").TargetCheckPlan} Immutable TypeScript plan.
11
+ */
12
+ export function createTypeScriptCheckPlan(context) {
13
+ const tool = checkTool(context, "tsc", "typescript")
14
+ const artifacts = checkArtifacts(context, artifact => artifact.path.endsWith(".ts") || path.basename(artifact.path) == "package.json",
15
+ "typescript", "only staged '.ts' artifacts and package manifests")
16
+ const sources = artifacts.filter(artifact => artifact.endsWith(".ts"))
17
+
18
+ if (sources.length == 0) {
19
+ throw new SemantifoldDiagnostic({code: "INVALID_TARGET_CHECK_PLAN", language: "typescript",
20
+ message: "TypeScript developer checks require at least one staged '.ts' artifact."})
21
+ }
22
+ const typeRoots = path.join(context.buildPath, "types")
23
+ const argv = [
24
+ "--pretty", "false", "--noEmit", "--incremental", "false", "--target", "ES2024", "--module", "NodeNext",
25
+ "--moduleResolution", "NodeNext", "--typeRoots", typeRoots, ...sources
26
+ ]
27
+
28
+ return checkPlan(context, "typescript", artifacts, [checkStage({
29
+ argv,
30
+ cwd: context.sourcePath,
31
+ inputs: artifacts,
32
+ output: null,
33
+ pathArguments: [pathArgument(12, "build"), ...sources.map((_, index) => pathArgument(13 + index, "source"))],
34
+ stage: "compile",
35
+ tool
36
+ })])
37
+ }
@@ -0,0 +1,81 @@
1
+ // @ts-check
2
+
3
+ import path from "node:path"
4
+ import {SemantifoldDiagnostic} from "../diagnostic.js"
5
+ import {
6
+ checkArtifacts,
7
+ checkPlan,
8
+ checkStage,
9
+ checkTool,
10
+ environmentPath,
11
+ pathArgument
12
+ } from "./check-plan.js"
13
+ import {zigBuild} from "./zig-runtime.js"
14
+
15
+ /**
16
+ * Constructs Zig's isolated Debug project build and canonical format-check plan.
17
+ * @param {import("../language-registry.js").TargetCheckPlanContext} context - Validated candidate context.
18
+ * @returns {import("../semantic/types.js").TargetCheckPlan} Immutable Zig plan.
19
+ */
20
+ export function createZigCheckPlan(context) {
21
+ const tool = checkTool(context, "zig", "zig")
22
+ const artifacts = checkArtifacts(context, artifact => artifact.path == "build.zig" || artifact.path.endsWith(".zig"),
23
+ "zig", "only staged Zig source and the canonical build manifest")
24
+ const manifests = context.artifacts.artifacts.filter(artifact => artifact.path == "build.zig")
25
+ const sources = artifacts.filter(artifact => artifact != path.join(context.sourcePath, "build.zig"))
26
+
27
+ if (manifests.length != 1 || manifests[0].contentKind != "text" || manifests[0].role != "manifest" ||
28
+ manifests[0].content != zigBuild || artifacts.length != 2 || sources.length != 1 ||
29
+ sources[0] != path.join(context.sourcePath, "src/main.zig")) {
30
+ throw new SemantifoldDiagnostic({
31
+ code: "INVALID_TARGET_CHECK_PLAN",
32
+ language: "zig",
33
+ message: "Zig developer checks require the exact standard-library-only 'build.zig' and staged Zig source."
34
+ })
35
+ }
36
+ const home = path.join(context.buildPath, "home")
37
+ const temporary = path.join(context.buildPath, "tmp")
38
+ const globalCache = path.join(context.buildPath, "zig-global-cache")
39
+ const localCache = path.join(context.buildPath, "zig-local-cache")
40
+ const output = path.join(context.buildPath, "output")
41
+ const environment = {
42
+ HOME: home,
43
+ HTTP_PROXY: "http://127.0.0.1:9",
44
+ HTTPS_PROXY: "http://127.0.0.1:9",
45
+ NO_PROXY: "",
46
+ TMPDIR: temporary,
47
+ ZIG_GLOBAL_CACHE_DIR: globalCache,
48
+ ZIG_LOCAL_CACHE_DIR: localCache
49
+ }
50
+ const environmentPaths = [
51
+ environmentPath("HOME", "build"), environmentPath("TMPDIR", "build"),
52
+ environmentPath("ZIG_GLOBAL_CACHE_DIR", "build"), environmentPath("ZIG_LOCAL_CACHE_DIR", "build")
53
+ ]
54
+ const formatArgv = ["fmt", "--check", ...artifacts]
55
+
56
+ return checkPlan(context, "zig", artifacts, [
57
+ checkStage({
58
+ argv: ["build", "-Doptimize=Debug", "--prefix", output],
59
+ cwd: context.sourcePath,
60
+ environment,
61
+ environmentPaths,
62
+ inputs: artifacts,
63
+ output: null,
64
+ pathArguments: [pathArgument(3, "build")],
65
+ stage: "compile",
66
+ tool,
67
+ transientPaths: [output]
68
+ }),
69
+ checkStage({
70
+ argv: formatArgv,
71
+ cwd: context.sourcePath,
72
+ environment,
73
+ environmentPaths,
74
+ inputs: artifacts,
75
+ output: null,
76
+ pathArguments: artifacts.map((_, index) => pathArgument(index + 2, "source")),
77
+ stage: "validate",
78
+ tool
79
+ })
80
+ ])
81
+ }
package/src/diagnostic.js CHANGED
@@ -19,8 +19,12 @@ export class SemantifoldDiagnostic extends Error {
19
19
  * @param {string | undefined} [options.stderr] - Captured standard error when available.
20
20
  * @param {string | undefined} [options.stdout] - Captured standard output when available.
21
21
  * @param {string | undefined} [options.version] - Captured executable version when known.
22
+ * @param {number | undefined} [options.durationMs] - Observed process duration when known.
23
+ * @param {string | undefined} [options.projectId] - Exact project identity when known.
24
+ * @param {string | undefined} [options.targetId] - Exact project target identity when known.
25
+ * @param {string | undefined} [options.toolId] - Exact toolchain identity when known.
22
26
  */
23
- constructor({cause, code, command, executable, exitCode, generatedLocation, language, location, message, signal, stage, stderr, stdout, version}) {
27
+ constructor({cause, code, command, durationMs, executable, exitCode, generatedLocation, language, location, message, projectId, signal, stage, stderr, stdout, targetId, toolId, version}) {
24
28
  const locationText = location ? ` at ${location.filename}:${location.start.line}:${location.start.column}` : ""
25
29
 
26
30
  super(`[${code}] ${language}${locationText}: ${message}`, cause ? {cause} : undefined)
@@ -31,12 +35,16 @@ export class SemantifoldDiagnostic extends Error {
31
35
  this.language = language
32
36
  this.location = location
33
37
  if (command != undefined) this.command = command
38
+ if (durationMs != undefined) this.durationMs = durationMs
34
39
  if (executable != undefined) this.executable = executable
35
40
  if (exitCode != undefined) this.exitCode = exitCode
36
41
  if (signal != undefined) this.signal = signal
37
42
  if (stage != undefined) this.stage = stage
38
43
  if (stderr != undefined) this.stderr = stderr
39
44
  if (stdout != undefined) this.stdout = stdout
45
+ if (projectId != undefined) this.projectId = projectId
46
+ if (targetId != undefined) this.targetId = targetId
47
+ if (toolId != undefined) this.toolId = toolId
40
48
  if (version != undefined) this.version = version
41
49
  }
42
50
  }
@@ -19,6 +19,15 @@ import {inspectRubyModule} from "./ruby.js"
19
19
  const programLanguages = new Set(["php", "ruby", "javascript", "typescript", "java"])
20
20
  const moduleIdPattern = /^[a-z][a-z0-9_]*(?:[.-][a-z][a-z0-9_]*)*$/u
21
21
 
22
+ /**
23
+ * Reports whether a registered frontend participates in the explicit Task-010 program profile.
24
+ * @param {string} language - Registered source identity.
25
+ * @returns {boolean} Whether the profile accepts the language.
26
+ */
27
+ export function supportsProgramSourceLanguage(language) {
28
+ return programLanguages.has(/** @type {import("../semantic/types.js").SemanticLanguage} */ (language))
29
+ }
30
+
22
31
  /** @typedef {{facade?: import("../stdlib-facades.js").StdlibFacadeRecord, filename: string, id: string, language: import("../semantic/types.js").SemanticLanguage, ownership: "application" | "facade", source: string}} ProgramSource */
23
32
  /** @typedef {{declarationLocation?: import("../semantic/types.js").SourceLocation, facade?: import("../stdlib-facades.js").StdlibFacadeRecord, importedName: string, importedNameLocation?: import("../semantic/types.js").SourceLocation, localName: string, localNameLocation?: import("../semantic/types.js").SourceLocation, location: import("../semantic/types.js").SourceLocation, namespace?: boolean, pathLocation: import("../semantic/types.js").SourceLocation, specifier: string, stdlibCandidate?: true, typeOnly: boolean}} ProgramImportRequest */
24
33
  /** @typedef {{importedName: string, localName: string, location: import("../semantic/types.js").SourceLocation, nativeName: string, symbolKind: import("../semantic/types.js").SemanticDeclarationKind, typeOnly: boolean}} ProgramNativeBinding */
@@ -5,6 +5,7 @@ import {SemantifoldDiagnostic, unsupportedRole} from "./diagnostic.js"
5
5
  import {generateJava} from "./backends/java.js"
6
6
  import {generateKotlin} from "./backends/kotlin.js"
7
7
  import {generateCSharpProject} from "./backends/csharp.js"
8
+ import {createCSharpCheckPlan} from "./backends/csharp-check.js"
8
9
  import {generateGoModule} from "./backends/go.js"
9
10
  import {generateRustProject} from "./backends/rust.js"
10
11
  import {generateSwift} from "./backends/swift.js"
@@ -35,12 +36,27 @@ import {parseJavaScriptTypeScript} from "./frontends/javascript-typescript.js"
35
36
  import {parsePhp} from "./frontends/php.js"
36
37
  import {parsePython} from "./frontends/python.js"
37
38
  import {parseRuby} from "./frontends/ruby.js"
39
+ import {createJavaCheckPlan} from "./backends/java-check.js"
40
+ import {createJavaScriptCheckPlan} from "./backends/javascript-check.js"
41
+ import {createKotlinCheckPlan} from "./backends/kotlin-check.js"
42
+ import {createPhpCheckPlan} from "./backends/php-check.js"
43
+ import {createPythonCheckPlan} from "./backends/python-check.js"
44
+ import {createRubyCheckPlan} from "./backends/ruby-check.js"
45
+ import {createTypeScriptCheckPlan} from "./backends/typescript-check.js"
46
+ import {createGoCheckPlan} from "./backends/go-check.js"
47
+ import {createCCheckPlan} from "./backends/c-check.js"
48
+ import {createCppCheckPlan} from "./backends/cpp-check.js"
49
+ import {createRustCheckPlan} from "./backends/rust-check.js"
50
+ import {createSwiftCheckPlan} from "./backends/swift-check.js"
51
+ import {createDartCheckPlan} from "./backends/dart-check.js"
52
+ import {createZigCheckPlan} from "./backends/zig-check.js"
38
53
 
39
54
  const registryRoles = Object.freeze(["frontend", "textBackend", "binaryBackend", "applicationBackend", "interoperability"])
40
55
  const acceptanceStageOrder = ["parse", "generate", "restore", "compile", "link", "validate", "instantiate", "execute"]
41
56
  const acceptanceStages = new Map(acceptanceStageOrder.map((stage, index) => [stage, index]))
57
+ const developerCheckStages = new Set(["restore", "compile", "link", "validate"])
42
58
  const registryKeys = new Set([
43
- "acceptance", "applicationBackend", "artifactMultiplicity", "binaryBackend", "defaultFilename", "frontend", "id",
59
+ "acceptance", "applicationBackend", "artifactMultiplicity", "binaryBackend", "check", "defaultFilename", "frontend", "id",
44
60
  "features", "interoperability", "mapping", "mediaType", "provider", "roundTrip", "textBackend"
45
61
  ])
46
62
 
@@ -65,6 +81,7 @@ const registryKeys = new Set([
65
81
  * @typedef LanguageRegistryRecord
66
82
  * @property {string} id - Stable identity.
67
83
  * @property {{stages: import("./semantic/types.js").AcceptanceStage[], toolchains: string[]}} acceptance - Acceptance declaration.
84
+ * @property {Readonly<LanguageRegistryCheckRecord>} check - Developer-check declaration.
68
85
  * @property {"single" | "multiple"} artifactMultiplicity - Artifact multiplicity.
69
86
  * @property {import("./semantic/types.js").LanguageFeatureCapabilities} features - Semantic feature capabilities.
70
87
  * @property {import("./semantic/types.js").LanguageMappingCapabilities} mapping - Mapping capabilities.
@@ -79,6 +96,31 @@ const registryKeys = new Set([
79
96
  * @property {RegistryImplementation} [interoperability] - Interoperability bridge.
80
97
  */
81
98
 
99
+ /**
100
+ * @typedef {Readonly<{
101
+ * artifacts: import("./semantic/types.js").GeneratedArtifactSet,
102
+ * buildPath: string,
103
+ * projectId: string,
104
+ * sourcePath: string,
105
+ * targetId: string,
106
+ * tools: readonly import("./semantic/types.js").DiscoveredToolchain[]
107
+ * }>} TargetCheckPlanContext
108
+ */
109
+
110
+ /**
111
+ * @callback TargetCheckPlanFactory
112
+ * @param {TargetCheckPlanContext} context - Exact staged target context.
113
+ * @returns {import("./semantic/types.js").TargetCheckPlan} Immutable plan.
114
+ */
115
+
116
+ /**
117
+ * @typedef LanguageRegistryCheckRecord
118
+ * @property {TargetCheckPlanFactory} [factory] - Target-owned plan factory for supported checks.
119
+ * @property {readonly import("./semantic/types.js").AcceptanceStage[]} stages - Exact non-executing stages.
120
+ * @property {boolean} supported - Whether the target supplies a check plan.
121
+ * @property {readonly string[]} toolchains - Exact declared canonical toolchains.
122
+ */
123
+
82
124
  /**
83
125
  * @typedef LanguageRegistry
84
126
  * @property {readonly import("./semantic/types.js").LanguageCapabilities[]} descriptors - Public descriptors.
@@ -218,6 +260,52 @@ export function createLanguageRegistry(candidateRecords) {
218
260
  if (new Set(toolchains).size != toolchains.length) {
219
261
  invalidRegistry(`Registry record '${id}' has duplicate acceptance toolchains.`, id)
220
262
  }
263
+ const checkCandidate = candidate.check
264
+ /** @type {Readonly<LanguageRegistryCheckRecord>} */
265
+ let check
266
+
267
+ if (checkCandidate === undefined) {
268
+ check = deepFreeze({stages: [], supported: false, toolchains: []})
269
+ } else {
270
+ if (!isPlainObject(checkCandidate) || Object.keys(checkCandidate).sort().join(",") != "factory,stages,toolchains" ||
271
+ typeof checkCandidate.factory != "function" || !isDenseArray(checkCandidate.stages) ||
272
+ !isDenseArray(checkCandidate.toolchains) || checkCandidate.stages.length == 0) {
273
+ invalidRegistry(`Registry record '${id}' has an invalid developer-check declaration.`, id)
274
+ }
275
+ /** @type {unknown[]} */
276
+ const checkStageSnapshot = []
277
+ /** @type {unknown[]} */
278
+ const checkToolchainSnapshot = []
279
+
280
+ for (let index = 0; index < checkCandidate.stages.length; index += 1) {
281
+ checkStageSnapshot.push(checkCandidate.stages[index])
282
+ }
283
+ for (let index = 0; index < checkCandidate.toolchains.length; index += 1) {
284
+ checkToolchainSnapshot.push(checkCandidate.toolchains[index])
285
+ }
286
+ if (!checkStageSnapshot.every(stage => typeof stage == "string" && developerCheckStages.has(stage) &&
287
+ declaredStages.has(stage)) || !checkToolchainSnapshot.every(toolchain => typeof toolchain == "string" &&
288
+ toolchains.includes(toolchain)) || new Set(checkStageSnapshot).size != checkStageSnapshot.length ||
289
+ new Set(checkToolchainSnapshot).size != checkToolchainSnapshot.length) {
290
+ invalidRegistry(`Registry record '${id}' developer checks must use ordered non-executing declared stages and toolchains.`, id)
291
+ }
292
+ let previousCheckStage = -1
293
+
294
+ for (const stage of checkStageSnapshot) {
295
+ const stageIndex = /** @type {number} */ (acceptanceStages.get(/** @type {string} */ (stage)))
296
+
297
+ if (stageIndex < previousCheckStage) {
298
+ invalidRegistry(`Registry record '${id}' has unordered developer-check stages.`, id)
299
+ }
300
+ previousCheckStage = stageIndex
301
+ }
302
+ check = deepFreeze({
303
+ factory: /** @type {TargetCheckPlanFactory} */ (checkCandidate.factory),
304
+ stages: /** @type {import("./semantic/types.js").AcceptanceStage[]} */ (checkStageSnapshot),
305
+ supported: true,
306
+ toolchains: /** @type {string[]} */ (checkToolchainSnapshot)
307
+ })
308
+ }
221
309
 
222
310
  const hasFrontend = typeof candidate.frontend == "function"
223
311
  const hasTextBackend = typeof candidate.textBackend == "function"
@@ -225,6 +313,10 @@ export function createLanguageRegistry(candidateRecords) {
225
313
  const hasApplicationBackend = typeof candidate.applicationBackend == "function"
226
314
  const hasBackend = hasTextBackend || hasBinaryBackend || hasApplicationBackend
227
315
 
316
+ if (check.supported && !hasBackend) {
317
+ invalidRegistry(`Registry record '${id}' declares developer checks without a backend role.`, id)
318
+ }
319
+
228
320
  if ((mapping.richText || mapping.sourceMapV3 || mapping.binaryRanges) && !hasBackend ||
229
321
  mapping.sourceMapV3 && !mapping.richText ||
230
322
  mapping.binaryRanges && !hasBinaryBackend && !hasApplicationBackend) {
@@ -255,6 +347,7 @@ export function createLanguageRegistry(candidateRecords) {
255
347
  const record = deepFreeze(/** @type {LanguageRegistryRecord} */ ({
256
348
  acceptance,
257
349
  artifactMultiplicity,
350
+ check,
258
351
  features,
259
352
  id,
260
353
  mapping,
@@ -271,6 +364,7 @@ export function createLanguageRegistry(candidateRecords) {
271
364
  const descriptor = deepFreeze(/** @type {import("./semantic/types.js").LanguageCapabilities} */ ({
272
365
  acceptance,
273
366
  artifactMultiplicity,
367
+ check: deepFreeze({stages: check.stages, supported: check.supported, toolchains: check.toolchains}),
274
368
  features,
275
369
  id,
276
370
  mapping,
@@ -384,7 +478,8 @@ const zigFrontend = ({filename, source}) => parseZig({filename, source})
384
478
 
385
479
  const records = [
386
480
  language({
387
- acceptance: {stages: ["parse", "generate", "execute"], toolchains: ["php82"]},
481
+ acceptance: {stages: ["parse", "generate", "validate", "execute"], toolchains: ["php82"]},
482
+ check: {factory: createPhpCheckPlan, stages: ["validate"], toolchains: ["php82"]},
388
483
  defaultFilename: "program.php",
389
484
  frontend: phpFrontend,
390
485
  id: "php",
@@ -392,7 +487,8 @@ const records = [
392
487
  textBackend: generatePhp
393
488
  }),
394
489
  language({
395
- acceptance: {stages: ["parse", "generate", "execute"], toolchains: ["ruby"]},
490
+ acceptance: {stages: ["parse", "generate", "validate", "execute"], toolchains: ["ruby"]},
491
+ check: {factory: createRubyCheckPlan, stages: ["validate"], toolchains: ["ruby"]},
396
492
  defaultFilename: "program.rb",
397
493
  frontend: rubyFrontend,
398
494
  id: "ruby",
@@ -400,7 +496,8 @@ const records = [
400
496
  textBackend: generateRuby
401
497
  }),
402
498
  language({
403
- acceptance: {stages: ["parse", "generate", "execute"], toolchains: ["node"]},
499
+ acceptance: {stages: ["parse", "generate", "validate", "execute"], toolchains: ["node"]},
500
+ check: {factory: createJavaScriptCheckPlan, stages: ["validate"], toolchains: ["node"]},
404
501
  defaultFilename: "program.js",
405
502
  frontend: javaScriptFrontend,
406
503
  id: "javascript",
@@ -409,6 +506,7 @@ const records = [
409
506
  }),
410
507
  language({
411
508
  acceptance: {stages: ["parse", "generate", "compile", "execute"], toolchains: ["tsc", "node"]},
509
+ check: {factory: createTypeScriptCheckPlan, stages: ["compile"], toolchains: ["tsc"]},
412
510
  defaultFilename: "program.ts",
413
511
  frontend: typeScriptFrontend,
414
512
  id: "typescript",
@@ -417,6 +515,7 @@ const records = [
417
515
  }),
418
516
  language({
419
517
  acceptance: {stages: ["parse", "generate", "compile", "execute"], toolchains: ["javac", "java"]},
518
+ check: {factory: createJavaCheckPlan, stages: ["compile"], toolchains: ["javac"]},
420
519
  defaultFilename: "Main.java",
421
520
  frontend: javaFrontend,
422
521
  id: "java",
@@ -425,6 +524,7 @@ const records = [
425
524
  }),
426
525
  language({
427
526
  acceptance: {stages: ["parse", "generate", "compile", "execute"], toolchains: ["kotlinc", "java25"]},
527
+ check: {factory: createKotlinCheckPlan, stages: ["compile"], toolchains: ["kotlinc"]},
428
528
  defaultFilename: "Program.kt",
429
529
  frontend: kotlinFrontend,
430
530
  id: "kotlin",
@@ -433,6 +533,7 @@ const records = [
433
533
  }),
434
534
  language({
435
535
  acceptance: {stages: ["parse", "generate", "compile", "execute"], toolchains: ["python"]},
536
+ check: {factory: createPythonCheckPlan, stages: ["compile"], toolchains: ["python"]},
436
537
  defaultFilename: "program.py",
437
538
  frontend: pythonFrontend,
438
539
  id: "python",
@@ -442,6 +543,7 @@ const records = [
442
543
  language({
443
544
  acceptance: {stages: ["parse", "generate", "restore", "compile", "execute"], toolchains: ["dotnet"]},
444
545
  artifactMultiplicity: "multiple",
546
+ check: {factory: createCSharpCheckPlan, stages: ["restore", "compile"], toolchains: ["dotnet"]},
445
547
  defaultFilename: "Program.cs",
446
548
  frontend: csharpFrontend,
447
549
  id: "csharp",
@@ -451,6 +553,7 @@ const records = [
451
553
  language({
452
554
  acceptance: {stages: ["parse", "generate", "compile", "validate", "execute"], toolchains: ["go"]},
453
555
  artifactMultiplicity: "multiple",
556
+ check: {factory: createGoCheckPlan, stages: ["compile", "validate"], toolchains: ["go"]},
454
557
  defaultFilename: "main.go",
455
558
  frontend: goFrontend,
456
559
  id: "go",
@@ -460,6 +563,7 @@ const records = [
460
563
  language({
461
564
  acceptance: {stages: ["parse", "generate", "compile", "link", "execute"], toolchains: ["clang"]},
462
565
  artifactMultiplicity: "multiple",
566
+ check: {factory: createCCheckPlan, stages: ["compile", "link"], toolchains: ["clang"]},
463
567
  defaultFilename: "program.c",
464
568
  frontend: parseC,
465
569
  id: "c",
@@ -468,18 +572,22 @@ const records = [
468
572
  }),
469
573
  language({
470
574
  acceptance: {stages: ["parse", "generate", "compile", "link", "execute"], toolchains: ["clangpp"]},
575
+ check: {factory: createCppCheckPlan, stages: ["compile", "link"], toolchains: ["clangpp"]},
471
576
  defaultFilename: "program.cpp", frontend: parseCpp, id: "cpp", mediaType: "text/x-c++src", textBackend: generateCpp
472
577
  }),
473
578
  language({
474
579
  acceptance: {stages: ["parse", "generate", "compile", "validate", "execute"], toolchains: ["rustc", "cargo"]},
475
580
  artifactMultiplicity: "multiple",
581
+ check: {factory: createRustCheckPlan, stages: ["compile", "validate"], toolchains: ["rustc", "cargo"]},
476
582
  defaultFilename: "src/main.rs", frontend: parseRust, id: "rust", mediaType: "text/x-rust", textBackend: generateRustProject
477
583
  }),
478
584
  language({acceptance: {stages: ["parse", "generate", "compile", "execute"], toolchains: ["swiftc"]},
585
+ check: {factory: createSwiftCheckPlan, stages: ["compile"], toolchains: ["swiftc"]},
479
586
  defaultFilename: "program.swift", frontend: parseSwift, id: "swift", mediaType: "text/x-swift", textBackend: generateSwift}),
480
587
  language({
481
588
  acceptance: {stages: ["parse", "generate", "restore", "compile", "validate", "execute"], toolchains: ["dart"]},
482
589
  artifactMultiplicity: "multiple",
590
+ check: {factory: createDartCheckPlan, stages: ["restore", "compile", "validate"], toolchains: ["dart"]},
483
591
  defaultFilename: "bin/program.dart",
484
592
  features: {
485
593
  closedRecords: false,
@@ -502,6 +610,7 @@ const records = [
502
610
  language({
503
611
  acceptance: {stages: ["parse", "generate", "compile", "validate", "execute"], toolchains: ["zig"]},
504
612
  artifactMultiplicity: "multiple",
613
+ check: {factory: createZigCheckPlan, stages: ["compile", "validate"], toolchains: ["zig"]},
505
614
  defaultFilename: "src/main.zig",
506
615
  features: {
507
616
  closedRecords: false,