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,117 @@
1
+ // @ts-check
2
+
3
+ import {createHash} from "node:crypto"
4
+ import path from "node:path"
5
+ import {SemantifoldDiagnostic} from "../diagnostic.js"
6
+ import {
7
+ checkArtifacts,
8
+ checkPlan,
9
+ checkStage,
10
+ checkTool,
11
+ environmentPath,
12
+ pathArgument
13
+ } from "./check-plan.js"
14
+ import {dartLockfile, dartPubspec} from "./dart.js"
15
+
16
+ /**
17
+ * Constructs Dart's offline package verification, native compile, format and analysis plan.
18
+ * @param {import("../language-registry.js").TargetCheckPlanContext} context - Validated candidate context.
19
+ * @returns {import("../semantic/types.js").TargetCheckPlan} Immutable Dart plan.
20
+ */
21
+ export function createDartCheckPlan(context) {
22
+ const tool = checkTool(context, "dart", "dart")
23
+ const artifacts = checkArtifacts(context, artifact => artifact.path.endsWith(".dart") ||
24
+ artifact.path == "pubspec.yaml" || artifact.path == "pubspec.lock",
25
+ "dart", "only staged Dart source and canonical pub package/lock artifacts")
26
+ const pubspecs = context.artifacts.artifacts.filter(artifact => artifact.path == "pubspec.yaml")
27
+ const lockfiles = context.artifacts.artifacts.filter(artifact => artifact.path == "pubspec.lock")
28
+ const sources = artifacts.filter(artifact => artifact.endsWith(".dart"))
29
+
30
+ if (pubspecs.length != 1 || pubspecs[0].contentKind != "text" || pubspecs[0].role != "manifest" ||
31
+ pubspecs[0].content != dartPubspec || lockfiles.length != 1 || lockfiles[0].contentKind != "text" ||
32
+ lockfiles[0].role != "manifest" || lockfiles[0].content != dartLockfile || artifacts.length != 3 || sources.length != 1 ||
33
+ sources[0] != path.join(context.sourcePath, "bin/program.dart")) {
34
+ throw new SemantifoldDiagnostic({
35
+ code: "INVALID_TARGET_CHECK_PLAN",
36
+ language: "dart",
37
+ message: "Dart developer checks require the exact dependency-free pub package/lock and staged '.dart' source."
38
+ })
39
+ }
40
+ const restoreArtifacts = context.artifacts.artifacts.filter(artifact =>
41
+ artifact.path == "pubspec.yaml" || artifact.path == "pubspec.lock").sort((left, right) => left.path.localeCompare(right.path, "en"))
42
+ const restoreInputs = Object.freeze(restoreArtifacts.map(artifact => path.join(context.sourcePath, artifact.path)))
43
+ const restoreHash = createHash("sha256")
44
+
45
+ for (const artifact of restoreArtifacts) {
46
+ const contentLength = typeof artifact.content == "string" ? Buffer.byteLength(artifact.content) : artifact.content.byteLength
47
+
48
+ restoreHash.update(`${Buffer.byteLength(artifact.path)}:`).update(artifact.path)
49
+ .update(`${contentLength}:`).update(artifact.content)
50
+ }
51
+ const home = path.join(context.buildPath, "home")
52
+ const pubCache = path.join(context.buildPath, "pub-cache")
53
+ const temporary = path.join(context.buildPath, "tmp")
54
+ const environment = {
55
+ CI: "true",
56
+ DART_SUPPRESS_ANALYTICS: "true",
57
+ HOME: home,
58
+ PUB_CACHE: pubCache,
59
+ PUB_HOSTED_URL: "http://127.0.0.1:9",
60
+ TMPDIR: temporary
61
+ }
62
+ const environmentPaths = [environmentPath("HOME", "build"), environmentPath("PUB_CACHE", "build"),
63
+ environmentPath("TMPDIR", "build")]
64
+ const nativeOutput = path.join(context.buildPath, "native-output")
65
+ const binary = path.join(nativeOutput, "semantifold-dart")
66
+ const compileArgv = ["compile", "exe", sources[0], "-o", binary]
67
+
68
+ return checkPlan(context, "dart", artifacts, [
69
+ checkStage({
70
+ argv: ["pub", "get", "--offline", "--dry-run", "--enforce-lockfile", "--no-precompile"],
71
+ cwd: context.sourcePath,
72
+ environment,
73
+ environmentPaths,
74
+ inputHash: restoreHash.digest("hex"),
75
+ inputs: restoreInputs,
76
+ output: null,
77
+ pathArguments: [],
78
+ stage: "restore",
79
+ tool,
80
+ transientPaths: [path.join(context.sourcePath, ".dart_tool")]
81
+ }),
82
+ checkStage({
83
+ argv: compileArgv,
84
+ cwd: context.sourcePath,
85
+ environment,
86
+ environmentPaths,
87
+ inputs: artifacts,
88
+ output: null,
89
+ pathArguments: [pathArgument(2, "source"), pathArgument(4, "build")],
90
+ stage: "compile",
91
+ tool,
92
+ transientPaths: [nativeOutput]
93
+ }),
94
+ checkStage({
95
+ argv: ["format", "--output=none", "--set-exit-if-changed", sources[0]],
96
+ cwd: context.sourcePath,
97
+ environment,
98
+ environmentPaths,
99
+ inputs: sources,
100
+ output: null,
101
+ pathArguments: [pathArgument(3, "source")],
102
+ stage: "validate",
103
+ tool
104
+ }),
105
+ checkStage({
106
+ argv: ["analyze", "--fatal-infos", "--fatal-warnings", context.sourcePath],
107
+ cwd: context.sourcePath,
108
+ environment,
109
+ environmentPaths,
110
+ inputs: artifacts,
111
+ output: null,
112
+ pathArguments: [pathArgument(3, "source")],
113
+ stage: "validate",
114
+ tool
115
+ })
116
+ ])
117
+ }
@@ -7,8 +7,8 @@ import {dartRuntime} from "./dart-runtime.js"
7
7
  import {emitScalarType} from "./scalars.js"
8
8
  import {SourceWriter} from "./writer.js"
9
9
 
10
- const pubspec = "name: semantifold_generated\npublish_to: none\nenvironment:\n sdk: 3.13.3\n"
11
- const lockfile = "# Generated by pub\n# See https://dart.dev/tools/pub/glossary#lockfile\npackages: {}\nsdks:\n dart: \"3.13.3\"\n"
10
+ export const dartPubspec = "name: semantifold_generated\npublish_to: none\nenvironment:\n sdk: 3.13.3\n"
11
+ export const dartLockfile = "# Generated by pub\n# See https://dart.dev/tools/pub/glossary#lockfile\npackages: {}\nsdks:\n dart: \"3.13.3\"\n"
12
12
 
13
13
  /**
14
14
  * Emits one deterministic dependency-free Dart package candidate.
@@ -35,7 +35,7 @@ export function generateDartPackage({filename, mapDirective, module, sourceMapFi
35
35
 
36
36
  return {
37
37
  artifacts: [{
38
- content: pubspec,
38
+ content: dartPubspec,
39
39
  contentKind: "text",
40
40
  mediaType: "application/yaml",
41
41
  ownership: "generated",
@@ -47,7 +47,7 @@ export function generateDartPackage({filename, mapDirective, module, sourceMapFi
47
47
  },
48
48
  role: "manifest"
49
49
  }, {
50
- content: lockfile,
50
+ content: dartLockfile,
51
51
  contentKind: "text",
52
52
  mediaType: "application/yaml",
53
53
  ownership: "generated",
@@ -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
+ import {goModuleManifest} from "./go.js"
15
+
16
+ /**
17
+ * Constructs Go's cgo-disabled, offline build/vet plan.
18
+ * @param {import("../language-registry.js").TargetCheckPlanContext} context - Validated candidate context.
19
+ * @returns {import("../semantic/types.js").TargetCheckPlan} Immutable Go plan.
20
+ */
21
+ export function createGoCheckPlan(context) {
22
+ const tool = checkTool(context, "go", "go")
23
+ const artifacts = checkArtifacts(context, artifact => artifact.path.endsWith(".go") || artifact.path == "go.mod",
24
+ "go", "only staged '.go' sources and the canonical module manifest")
25
+ const manifests = context.artifacts.artifacts.filter(artifact => artifact.path == "go.mod")
26
+ const sources = artifacts.filter(artifact => artifact.endsWith(".go"))
27
+
28
+ if (manifests.length != 1 || manifests[0].contentKind != "text" || manifests[0].role != "manifest" ||
29
+ manifests[0].content != goModuleManifest || artifacts.length != 2 || sources.length != 1 ||
30
+ sources[0] != path.join(context.sourcePath, "main.go")) {
31
+ throw new SemantifoldDiagnostic({
32
+ code: "INVALID_TARGET_CHECK_PLAN",
33
+ language: "go",
34
+ message: "Go developer checks require the exact dependency-free 'go.mod' and at least one staged '.go' source."
35
+ })
36
+ }
37
+ const cache = path.join(context.buildPath, "go-cache")
38
+ const moduleCache = path.join(context.buildPath, "go-mod-cache")
39
+ const goPath = path.join(context.buildPath, "go-path")
40
+ const temporary = path.join(context.buildPath, "go-tmp")
41
+ const home = path.join(context.buildPath, "go-home")
42
+ const binary = path.join(context.buildPath, "semantifold-go")
43
+ const environment = {
44
+ CGO_ENABLED: "0",
45
+ GOARCH: "amd64",
46
+ GOCACHE: cache,
47
+ GOENV: "off",
48
+ GOMODCACHE: moduleCache,
49
+ GOOS: "linux",
50
+ GOPATH: goPath,
51
+ GOPROXY: "off",
52
+ GOSUMDB: "off",
53
+ GOTOOLCHAIN: "local",
54
+ GOTMPDIR: temporary,
55
+ GOVCS: "off",
56
+ GOWORK: "off",
57
+ GO_TELEMETRY_CHILD: "2",
58
+ HOME: home
59
+ }
60
+ const environmentPaths = [
61
+ environmentPath("GOCACHE", "build"), environmentPath("GOMODCACHE", "build"), environmentPath("GOPATH", "build"),
62
+ environmentPath("GOTMPDIR", "build"), environmentPath("HOME", "build")
63
+ ]
64
+
65
+ return checkPlan(context, "go", artifacts, [
66
+ checkStage({
67
+ argv: ["build", "-mod=readonly", "-trimpath", "-buildvcs=false", "-ldflags=-buildid=", "-o", binary, "."],
68
+ cwd: context.sourcePath,
69
+ environment,
70
+ environmentPaths,
71
+ inputs: artifacts,
72
+ output: checkOutput(context.buildPath, "application/x-executable", "compiler-output"),
73
+ pathArguments: [pathArgument(6, "build")],
74
+ stage: "compile",
75
+ tool
76
+ }),
77
+ checkStage({
78
+ argv: ["vet", "-mod=readonly", "."],
79
+ cwd: context.sourcePath,
80
+ environment,
81
+ environmentPaths,
82
+ inputs: artifacts,
83
+ output: null,
84
+ pathArguments: [],
85
+ stage: "validate",
86
+ tool
87
+ })
88
+ ])
89
+ }
@@ -6,7 +6,7 @@ import {validateBackendModule, emitExpression} from "./shared.js"
6
6
  import {emitScalarType} from "./scalars.js"
7
7
  import {SourceWriter} from "./writer.js"
8
8
 
9
- const manifest = "module example.com/semantifold/generated\n\ngo 1.26.0\n"
9
+ export const goModuleManifest = "module example.com/semantifold/generated\n\ngo 1.26.0\n"
10
10
  const binarySyntax = Object.freeze({
11
11
  BooleanAnd: "&&", BooleanEqual: "==", BooleanNotEqual: "!=", BooleanOr: "||",
12
12
  IntegerAdd: "+", IntegerEqual: "==", IntegerGreaterThan: ">", IntegerGreaterThanOrEqual: ">=",
@@ -38,7 +38,7 @@ export function generateGoModule({filename, mapDirective, module, sourceMapFilen
38
38
  if (!root) throw new Error("Validated Go module omitted its canonical root provenance.")
39
39
  return {
40
40
  artifacts: [{
41
- content: manifest,
41
+ content: goModuleManifest,
42
42
  contentKind: "text",
43
43
  mediaType: "text/plain",
44
44
  ownership: "generated",
@@ -0,0 +1,77 @@
1
+ // @ts-check
2
+
3
+ import path from "node:path"
4
+ import {SemantifoldDiagnostic} from "../diagnostic.js"
5
+ import {deterministicEnvironment} from "../toolchains.js"
6
+
7
+ /**
8
+ * Constructs Java's non-executing compiler plan from staged generated artifacts.
9
+ * @param {Readonly<{
10
+ * artifacts: import("../semantic/types.js").GeneratedArtifactSet,
11
+ * buildPath: string,
12
+ * projectId: string,
13
+ * sourcePath: string,
14
+ * targetId: string,
15
+ * tools: readonly import("../semantic/types.js").DiscoveredToolchain[]
16
+ * }>} context - Exact validated candidate context.
17
+ * @returns {import("../semantic/types.js").TargetCheckPlan} Immutable javac plan.
18
+ */
19
+ export function createJavaCheckPlan(context) {
20
+ const javac = context.tools.find(({id}) => id == "javac")
21
+
22
+ if (!javac) {
23
+ throw new SemantifoldDiagnostic({
24
+ code: "INVALID_TARGET_CHECK_PLAN",
25
+ language: "java",
26
+ message: "Java developer checks require the declared 'javac' toolchain."
27
+ })
28
+ }
29
+ const artifactPaths = context.artifacts.artifacts
30
+ .filter(artifact => artifact.path.endsWith(".java"))
31
+ .map(artifact => path.join(context.sourcePath, artifact.path))
32
+
33
+ if (artifactPaths.length == 0) {
34
+ throw new SemantifoldDiagnostic({
35
+ code: "INVALID_TARGET_CHECK_PLAN",
36
+ language: "java",
37
+ message: "Java developer checks require at least one staged '.java' artifact."
38
+ })
39
+ }
40
+ const argv = Object.freeze(["-d", context.buildPath, ...artifactPaths])
41
+ const pathArguments = Object.freeze([
42
+ Object.freeze({index: 1, ownership: /** @type {const} */ ("build")}),
43
+ ...artifactPaths.map((_, index) => Object.freeze({index: index + 2, ownership: /** @type {const} */ ("source")}))
44
+ ])
45
+ const stage = Object.freeze({
46
+ argv,
47
+ cwd: context.sourcePath,
48
+ environment: deterministicEnvironment({}),
49
+ environmentPaths: Object.freeze([]),
50
+ executable: javac.executable,
51
+ inputHash: null,
52
+ inputs: Object.freeze(artifactPaths),
53
+ output: Object.freeze({
54
+ mediaType: "application/java-vm",
55
+ ownership: /** @type {const} */ ("build"),
56
+ path: context.buildPath,
57
+ role: "compiler-output"
58
+ }),
59
+ pathArguments,
60
+ stage: /** @type {const} */ ("compile"),
61
+ tool: javac,
62
+ transientPaths: Object.freeze([])
63
+ })
64
+
65
+ return Object.freeze({
66
+ artifactPaths: Object.freeze(artifactPaths),
67
+ buildPath: context.buildPath,
68
+ mode: /** @type {const} */ ("developer-check"),
69
+ projectId: context.projectId,
70
+ schema: /** @type {const} */ ("SemantifoldTargetCheckPlan"),
71
+ sourcePath: context.sourcePath,
72
+ stages: Object.freeze([stage]),
73
+ target: "java",
74
+ targetId: context.targetId,
75
+ version: /** @type {const} */ (1)
76
+ })
77
+ }
@@ -0,0 +1,33 @@
1
+ // @ts-check
2
+
3
+ import path from "node:path"
4
+ import {checkArtifacts, checkPlan, checkStage, checkTool, pathArgument} from "./check-plan.js"
5
+ import {SemantifoldDiagnostic} from "../diagnostic.js"
6
+
7
+ /**
8
+ * Constructs JavaScript's non-executing parse-check plan.
9
+ * @param {import("../language-registry.js").TargetCheckPlanContext} context - Validated candidate context.
10
+ * @returns {import("../semantic/types.js").TargetCheckPlan} Immutable JavaScript plan.
11
+ */
12
+ export function createJavaScriptCheckPlan(context) {
13
+ const tool = checkTool(context, "node", "javascript")
14
+ const artifacts = checkArtifacts(context, artifact => artifact.path.endsWith(".js") || path.basename(artifact.path) == "package.json",
15
+ "javascript", "only staged '.js' artifacts and package manifests")
16
+ const sources = artifacts.filter(artifact => artifact.endsWith(".js"))
17
+ const manifests = artifacts.filter(artifact => artifact.endsWith("package.json"))
18
+
19
+ if (sources.length == 0) {
20
+ throw new SemantifoldDiagnostic({code: "INVALID_TARGET_CHECK_PLAN", language: "javascript",
21
+ message: "JavaScript developer checks require at least one staged '.js' artifact."})
22
+ }
23
+
24
+ return checkPlan(context, "javascript", artifacts, sources.map((source, index) => checkStage({
25
+ argv: ["--check", source],
26
+ cwd: context.sourcePath,
27
+ inputs: [source, ...(index == 0 ? manifests : [])],
28
+ output: null,
29
+ pathArguments: [pathArgument(1, "source")],
30
+ stage: "validate",
31
+ tool
32
+ })))
33
+ }
@@ -0,0 +1,41 @@
1
+ // @ts-check
2
+
3
+ import path from "node:path"
4
+ import {
5
+ checkArtifacts,
6
+ checkOutput,
7
+ checkPlan,
8
+ checkStage,
9
+ checkTool,
10
+ environmentPath,
11
+ pathArgument
12
+ } from "./check-plan.js"
13
+
14
+ /**
15
+ * Constructs Kotlin/JVM's non-executing compiler plan.
16
+ * @param {import("../language-registry.js").TargetCheckPlanContext} context - Validated candidate context.
17
+ * @returns {import("../semantic/types.js").TargetCheckPlan} Immutable Kotlin plan.
18
+ */
19
+ export function createKotlinCheckPlan(context) {
20
+ const tool = checkTool(context, "kotlinc", "kotlin")
21
+ const artifacts = checkArtifacts(context, artifact => artifact.path.endsWith(".kt"), "kotlin", "only staged '.kt' artifacts")
22
+ const classes = path.join(context.buildPath, "classes")
23
+ const home = path.join(context.buildPath, "home")
24
+ const cache = path.join(context.buildPath, "cache")
25
+ const temporary = path.join(context.buildPath, "tmp")
26
+
27
+ return checkPlan(context, "kotlin", artifacts, [checkStage({
28
+ argv: ["-language-version", "2.4", "-api-version", "2.4", "-jvm-target", "25", "-Werror", ...artifacts, "-d", classes],
29
+ cwd: context.sourcePath,
30
+ environment: {HOME: home, TMPDIR: temporary, XDG_CACHE_HOME: cache},
31
+ environmentPaths: [environmentPath("HOME", "build"), environmentPath("TMPDIR", "build"), environmentPath("XDG_CACHE_HOME", "build")],
32
+ inputs: artifacts,
33
+ output: checkOutput(context.buildPath, "application/java-vm", "compiler-output"),
34
+ pathArguments: [
35
+ ...artifacts.map((_, index) => pathArgument(7 + index, "source")),
36
+ pathArgument(8 + artifacts.length, "build")
37
+ ],
38
+ stage: "compile",
39
+ tool
40
+ })])
41
+ }
@@ -0,0 +1,23 @@
1
+ // @ts-check
2
+
3
+ import {checkArtifacts, checkPlan, checkStage, checkTool, pathArgument} from "./check-plan.js"
4
+
5
+ /**
6
+ * Constructs PHP's non-executing syntax-check plan.
7
+ * @param {import("../language-registry.js").TargetCheckPlanContext} context - Validated candidate context.
8
+ * @returns {import("../semantic/types.js").TargetCheckPlan} Immutable PHP plan.
9
+ */
10
+ export function createPhpCheckPlan(context) {
11
+ const tool = checkTool(context, "php82", "php")
12
+ const artifacts = checkArtifacts(context, artifact => artifact.path.endsWith(".php"), "php", "only staged '.php' artifacts")
13
+
14
+ return checkPlan(context, "php", artifacts, artifacts.map(artifact => checkStage({
15
+ argv: ["-n", "-l", artifact],
16
+ cwd: context.sourcePath,
17
+ inputs: [artifact],
18
+ output: null,
19
+ pathArguments: [pathArgument(2, "source")],
20
+ stage: "validate",
21
+ tool
22
+ })))
23
+ }
@@ -25,6 +25,23 @@ const programTargets = new Set(["php", "ruby", "javascript", "typescript", "java
25
25
  /** @type {Readonly<Set<import("../semantic/types.js").BackendLanguage>>} */
26
26
  const programApplicationTargets = new Set(["android", "ios", "flutter"])
27
27
 
28
+ /**
29
+ * Reports whether program generation implements one registered target/role combination.
30
+ * @param {string} language - Registered target identity.
31
+ * @param {string} role - Explicit project target role.
32
+ * @returns {boolean} Whether complete semantic programs support the combination.
33
+ */
34
+ export function supportsProgramArtifactRole(language, role) {
35
+ if (role == "text") {
36
+ return programTargets.has(/** @type {import("../semantic/types.js").SemanticLanguage} */ (language))
37
+ }
38
+ if (role == "application") {
39
+ return programApplicationTargets.has(/** @type {import("../semantic/types.js").BackendLanguage} */ (language))
40
+ }
41
+
42
+ return false
43
+ }
44
+
28
45
  /**
29
46
  * Validates and prepares a complete semantic program for a non-text backend without allocating a writer.
30
47
  * @param {object} input - Backend preflight request.
@@ -0,0 +1,30 @@
1
+ // @ts-check
2
+
3
+ import path from "node:path"
4
+ import {checkArtifacts, checkOutput, checkPlan, checkStage, checkTool, pathArgument} from "./check-plan.js"
5
+
6
+ /**
7
+ * Constructs Python's isolated bytecode compiler plan.
8
+ * @param {import("../language-registry.js").TargetCheckPlanContext} context - Validated candidate context.
9
+ * @returns {import("../semantic/types.js").TargetCheckPlan} Immutable Python plan.
10
+ */
11
+ export function createPythonCheckPlan(context) {
12
+ const tool = checkTool(context, "python", "python")
13
+ const artifacts = checkArtifacts(context, artifact => artifact.path.endsWith(".py"), "python", "only staged '.py' artifacts")
14
+ const compiler = "import py_compile,sys;[py_compile.compile(sys.argv[index],cfile=sys.argv[index+1],dfile=sys.argv[index+2],doraise=True,invalidation_mode=py_compile.PycInvalidationMode.CHECKED_HASH) for index in range(1,len(sys.argv),3)]"
15
+ const arguments_ = artifacts.flatMap(artifactPath => [
16
+ artifactPath,
17
+ path.join(context.buildPath, `${path.basename(artifactPath, ".py")}.pyc`),
18
+ path.basename(artifactPath)
19
+ ])
20
+
21
+ return checkPlan(context, "python", artifacts, [checkStage({
22
+ argv: ["-I", "-B", "-c", compiler, ...arguments_],
23
+ cwd: context.sourcePath,
24
+ inputs: artifacts,
25
+ output: checkOutput(context.buildPath, "application/x-python-bytecode", "compiler-output"),
26
+ pathArguments: artifacts.flatMap((_, index) => [pathArgument(4 + index * 3, "source"), pathArgument(5 + index * 3, "build")]),
27
+ stage: "compile",
28
+ tool
29
+ })])
30
+ }
@@ -0,0 +1,23 @@
1
+ // @ts-check
2
+
3
+ import {checkArtifacts, checkPlan, checkStage, checkTool, pathArgument} from "./check-plan.js"
4
+
5
+ /**
6
+ * Constructs Ruby's non-executing syntax-check plan.
7
+ * @param {import("../language-registry.js").TargetCheckPlanContext} context - Validated candidate context.
8
+ * @returns {import("../semantic/types.js").TargetCheckPlan} Immutable Ruby plan.
9
+ */
10
+ export function createRubyCheckPlan(context) {
11
+ const tool = checkTool(context, "ruby", "ruby")
12
+ const artifacts = checkArtifacts(context, artifact => artifact.path.endsWith(".rb"), "ruby", "only staged '.rb' artifacts")
13
+
14
+ return checkPlan(context, "ruby", artifacts, artifacts.map(artifact => checkStage({
15
+ argv: ["--disable=gems", "-c", artifact],
16
+ cwd: context.sourcePath,
17
+ inputs: [artifact],
18
+ output: null,
19
+ pathArguments: [pathArgument(2, "source")],
20
+ stage: "validate",
21
+ tool
22
+ })))
23
+ }
@@ -0,0 +1,78 @@
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
+ environmentTool,
12
+ pathArgument
13
+ } from "./check-plan.js"
14
+ import {rustLockfile, rustManifest} from "./rust-runtime.js"
15
+
16
+ /**
17
+ * Constructs Rust's locked offline Cargo build/check plan.
18
+ * @param {import("../language-registry.js").TargetCheckPlanContext} context - Validated candidate context.
19
+ * @returns {import("../semantic/types.js").TargetCheckPlan} Immutable Cargo plan.
20
+ */
21
+ export function createRustCheckPlan(context) {
22
+ const rustc = checkTool(context, "rustc", "rust")
23
+ const cargo = checkTool(context, "cargo", "rust")
24
+ const artifacts = checkArtifacts(context, artifact => artifact.path.endsWith(".rs") ||
25
+ artifact.path == "Cargo.toml" || artifact.path == "Cargo.lock",
26
+ "rust", "only staged Rust source and canonical Cargo manifest/lock artifacts")
27
+ const manifest = context.artifacts.artifacts.filter(artifact => artifact.path == "Cargo.toml")
28
+ const lock = context.artifacts.artifacts.filter(artifact => artifact.path == "Cargo.lock")
29
+ const sources = artifacts.filter(artifact => artifact.endsWith(".rs"))
30
+
31
+ if (manifest.length != 1 || manifest[0].contentKind != "text" || manifest[0].role != "manifest" ||
32
+ manifest[0].content != rustManifest || lock.length != 1 || lock[0].contentKind != "text" ||
33
+ lock[0].content != rustLockfile || artifacts.length != 3 || sources.length != 1 ||
34
+ sources[0] != path.join(context.sourcePath, "src/main.rs")) {
35
+ throw new SemantifoldDiagnostic({
36
+ code: "INVALID_TARGET_CHECK_PLAN",
37
+ language: "rust",
38
+ message: "Rust developer checks require the exact dependency-free Cargo project/lock and staged '.rs' source."
39
+ })
40
+ }
41
+ const cargoHome = path.join(context.buildPath, "cargo-home")
42
+ const home = path.join(context.buildPath, "home")
43
+ const temporary = path.join(context.buildPath, "tmp")
44
+ const target = path.join(context.buildPath, "cargo-target")
45
+ const environment = {
46
+ CARGO_HOME: cargoHome,
47
+ CARGO_INCREMENTAL: "0",
48
+ CARGO_NET_OFFLINE: "true",
49
+ CARGO_TERM_COLOR: "never",
50
+ HOME: home,
51
+ PATH: [path.dirname(rustc.executable), path.dirname(cargo.executable), "/usr/local/bin", "/usr/bin", "/bin"].filter((value, index, values) =>
52
+ values.indexOf(value) == index).join(path.delimiter),
53
+ RUSTC: rustc.executable,
54
+ TMPDIR: temporary
55
+ }
56
+ const environmentPaths = [environmentPath("CARGO_HOME", "build"), environmentPath("HOME", "build"),
57
+ environmentTool("RUSTC", rustc), environmentPath("TMPDIR", "build")]
58
+ /**
59
+ * Constructs one Cargo stage over the complete generated project.
60
+ * @param {import("../semantic/types.js").AcceptanceStage} name - Registry stage identity.
61
+ * @param {string} command - Exact Cargo subcommand.
62
+ * @returns {import("../semantic/types.js").TargetCheckStageRequest} Immutable stage.
63
+ */
64
+ const stage = (name, command) => checkStage({
65
+ argv: [command, "--offline", "--locked", "--target-dir", target],
66
+ cwd: context.sourcePath,
67
+ environment,
68
+ environmentPaths,
69
+ inputs: artifacts,
70
+ output: null,
71
+ pathArguments: [pathArgument(4, "build")],
72
+ stage: name,
73
+ tool: cargo,
74
+ transientPaths: [target]
75
+ })
76
+
77
+ return checkPlan(context, "rust", artifacts, [stage("compile", "build"), stage("validate", "check")])
78
+ }