semantifold 0.9.0 → 0.11.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.
- package/README.md +6 -3
- package/bin/semantifold.js +6 -0
- package/build/bin/semantifold.d.ts +3 -0
- package/build/bin/semantifold.d.ts.map +1 -0
- package/build/bin/semantifold.js +5 -0
- package/build/index.d.ts +8 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +9 -1
- package/build/src/artifact-path.d.ts +16 -0
- package/build/src/artifact-path.d.ts.map +1 -1
- package/build/src/artifact-path.js +29 -3
- package/build/src/backends/c-check.d.ts +7 -0
- package/build/src/backends/c-check.d.ts.map +1 -0
- package/build/src/backends/c-check.js +65 -0
- package/build/src/backends/check-plan.d.ts +96 -0
- package/build/src/backends/check-plan.d.ts.map +1 -0
- package/build/src/backends/check-plan.js +135 -0
- package/build/src/backends/cpp-check.d.ts +7 -0
- package/build/src/backends/cpp-check.d.ts.map +1 -0
- package/build/src/backends/cpp-check.js +59 -0
- package/build/src/backends/csharp-check.d.ts +7 -0
- package/build/src/backends/csharp-check.d.ts.map +1 -0
- package/build/src/backends/csharp-check.js +125 -0
- package/build/src/backends/csharp.d.ts +1 -0
- package/build/src/backends/csharp.d.ts.map +1 -1
- package/build/src/backends/csharp.js +5 -4
- package/build/src/backends/dart-check.d.ts +7 -0
- package/build/src/backends/dart-check.d.ts.map +1 -0
- package/build/src/backends/dart-check.js +103 -0
- package/build/src/backends/dart.d.ts +2 -0
- package/build/src/backends/dart.d.ts.map +1 -1
- package/build/src/backends/dart.js +5 -5
- package/build/src/backends/go-check.d.ts +7 -0
- package/build/src/backends/go-check.d.ts.map +1 -0
- package/build/src/backends/go-check.js +77 -0
- package/build/src/backends/go.d.ts +1 -0
- package/build/src/backends/go.d.ts.map +1 -1
- package/build/src/backends/go.js +3 -3
- package/build/src/backends/java-check.d.ts +21 -0
- package/build/src/backends/java-check.d.ts.map +1 -0
- package/build/src/backends/java-check.js +73 -0
- package/build/src/backends/javascript-check.d.ts +7 -0
- package/build/src/backends/javascript-check.d.ts.map +1 -0
- package/build/src/backends/javascript-check.js +29 -0
- package/build/src/backends/kotlin-check.d.ts +7 -0
- package/build/src/backends/kotlin-check.d.ts.map +1 -0
- package/build/src/backends/kotlin-check.js +31 -0
- package/build/src/backends/kotlin.d.ts +1 -1
- package/build/src/backends/kotlin.js +2 -2
- package/build/src/backends/php-check.d.ts +7 -0
- package/build/src/backends/php-check.d.ts.map +1 -0
- package/build/src/backends/php-check.js +21 -0
- package/build/src/backends/program.d.ts +7 -0
- package/build/src/backends/program.d.ts.map +1 -1
- package/build/src/backends/program.js +16 -1
- package/build/src/backends/python-check.d.ts +7 -0
- package/build/src/backends/python-check.d.ts.map +1 -0
- package/build/src/backends/python-check.js +28 -0
- package/build/src/backends/ruby-check.d.ts +7 -0
- package/build/src/backends/ruby-check.d.ts.map +1 -0
- package/build/src/backends/ruby-check.js +21 -0
- package/build/src/backends/rust-check.d.ts +7 -0
- package/build/src/backends/rust-check.d.ts.map +1 -0
- package/build/src/backends/rust-check.js +65 -0
- package/build/src/backends/shared.d.ts.map +1 -1
- package/build/src/backends/shared.js +29 -1
- package/build/src/backends/swift-check.d.ts +7 -0
- package/build/src/backends/swift-check.d.ts.map +1 -0
- package/build/src/backends/swift-check.js +77 -0
- package/build/src/backends/typescript-check.d.ts +7 -0
- package/build/src/backends/typescript-check.d.ts.map +1 -0
- package/build/src/backends/typescript-check.js +33 -0
- package/build/src/backends/zig-check.d.ts +7 -0
- package/build/src/backends/zig-check.d.ts.map +1 -0
- package/build/src/backends/zig-check.js +70 -0
- package/build/src/diagnostic.d.ts +13 -1
- package/build/src/diagnostic.d.ts.map +1 -1
- package/build/src/diagnostic.js +14 -2
- package/build/src/frontends/java.d.ts.map +1 -1
- package/build/src/frontends/java.js +23 -1
- package/build/src/frontends/javascript-typescript.d.ts.map +1 -1
- package/build/src/frontends/javascript-typescript.js +45 -4
- package/build/src/frontends/php.d.ts.map +1 -1
- package/build/src/frontends/php.js +54 -3
- package/build/src/frontends/program.d.ts +6 -0
- package/build/src/frontends/program.d.ts.map +1 -1
- package/build/src/frontends/program.js +9 -1
- package/build/src/frontends/ruby.d.ts.map +1 -1
- package/build/src/frontends/ruby.js +55 -5
- package/build/src/language-registry.d.ts +54 -0
- package/build/src/language-registry.d.ts.map +1 -1
- package/build/src/language-registry.js +124 -10
- package/build/src/project-build.d.ts +172 -0
- package/build/src/project-build.d.ts.map +1 -0
- package/build/src/project-build.js +320 -0
- package/build/src/project-cli.d.ts +40 -0
- package/build/src/project-cli.d.ts.map +1 -0
- package/build/src/project-cli.js +145 -0
- package/build/src/project-manifest.d.ts +148 -0
- package/build/src/project-manifest.d.ts.map +1 -0
- package/build/src/project-manifest.js +432 -0
- package/build/src/project-reporter.d.ts +81 -0
- package/build/src/project-reporter.d.ts.map +1 -0
- package/build/src/project-reporter.js +293 -0
- package/build/src/project-snapshot.d.ts +129 -0
- package/build/src/project-snapshot.d.ts.map +1 -0
- package/build/src/project-snapshot.js +362 -0
- package/build/src/project-watch-reporter.d.ts +125 -0
- package/build/src/project-watch-reporter.d.ts.map +1 -0
- package/build/src/project-watch-reporter.js +280 -0
- package/build/src/project-watch.d.ts +133 -0
- package/build/src/project-watch.d.ts.map +1 -0
- package/build/src/project-watch.js +839 -0
- package/build/src/publication.d.ts +69 -5
- package/build/src/publication.d.ts.map +1 -1
- package/build/src/publication.js +246 -57
- package/build/src/semantic/effects.js +3 -1
- package/build/src/semantic/provenance.d.ts.map +1 -1
- package/build/src/semantic/provenance.js +11 -1
- package/build/src/semantic/types.d.ts +355 -4
- package/build/src/semantic/types.d.ts.map +1 -1
- package/build/src/semantic/types.js +92 -3
- package/build/src/semantic/validate.js +18 -1
- package/build/src/subprocess.d.ts +8 -0
- package/build/src/subprocess.d.ts.map +1 -1
- package/build/src/subprocess.js +50 -9
- package/build/src/target-check.d.ts +52 -0
- package/build/src/target-check.d.ts.map +1 -0
- package/build/src/target-check.js +796 -0
- package/build/src/toolchains.d.ts.map +1 -1
- package/build/src/toolchains.js +3 -3
- package/docs/adr-expression-breadth.md +186 -0
- package/docs/architecture.md +3 -1
- package/docs/c.md +4 -0
- package/docs/cpp.md +4 -0
- package/docs/dart.md +4 -0
- package/docs/generated-artifact-publication.md +11 -8
- package/docs/kotlin.md +2 -2
- package/docs/language-support.md +40 -6
- package/docs/parser-qualification.md +1 -1
- package/docs/project-build-cli.md +147 -0
- package/docs/project-watch.md +60 -0
- package/docs/rust.md +4 -0
- package/docs/swift.md +2 -0
- package/docs/testing.md +70 -3
- package/docs/watch-build-pipeline.md +39 -23
- package/docs/zig.md +2 -0
- package/examples/jsdoc-java-watch/expected-output.txt +3 -0
- package/examples/jsdoc-java-watch/semantifold.json +23 -0
- package/examples/jsdoc-java-watch/src/main.js +21 -0
- package/index.js +8 -0
- package/package.json +6 -1
- package/src/artifact-path.js +31 -2
- package/src/backends/c-check.js +80 -0
- package/src/backends/check-plan.js +147 -0
- package/src/backends/cpp-check.js +73 -0
- package/src/backends/csharp-check.js +139 -0
- package/src/backends/csharp.js +4 -3
- package/src/backends/dart-check.js +117 -0
- package/src/backends/dart.js +4 -4
- package/src/backends/go-check.js +89 -0
- package/src/backends/go.js +2 -2
- package/src/backends/java-check.js +77 -0
- package/src/backends/javascript-check.js +33 -0
- package/src/backends/kotlin-check.js +41 -0
- package/src/backends/kotlin.js +1 -1
- package/src/backends/php-check.js +23 -0
- package/src/backends/program.js +17 -0
- package/src/backends/python-check.js +30 -0
- package/src/backends/ruby-check.js +23 -0
- package/src/backends/rust-check.js +78 -0
- package/src/backends/shared.js +30 -0
- package/src/backends/swift-check.js +89 -0
- package/src/backends/typescript-check.js +37 -0
- package/src/backends/zig-check.js +81 -0
- package/src/diagnostic.js +9 -1
- package/src/frontends/java.js +24 -0
- package/src/frontends/javascript-typescript.js +49 -2
- package/src/frontends/php.js +61 -2
- package/src/frontends/program.js +9 -0
- package/src/frontends/ruby.js +62 -2
- package/src/language-registry.js +130 -9
- package/src/project-build.js +353 -0
- package/src/project-cli.js +155 -0
- package/src/project-manifest.js +479 -0
- package/src/project-reporter.js +320 -0
- package/src/project-snapshot.js +403 -0
- package/src/project-watch-reporter.js +303 -0
- package/src/project-watch.js +870 -0
- package/src/publication.js +275 -58
- package/src/semantic/effects.js +1 -0
- package/src/semantic/provenance.js +8 -0
- package/src/semantic/types.js +101 -2
- package/src/semantic/validate.js +26 -0
- package/src/subprocess.js +49 -8
- package/src/target-check.js +844 -0
- package/src/toolchains.js +3 -2
- package/tsconfig.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Status and verified baseline
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Tasks 039–042 implement the strict project manifest, stable one-shot snapshot, deterministic generation orchestration, generic non-executing check-plan contract, Java/`javac`, the interpreted/managed cohort, the native/project cohort, human/NDJSON reporting, and packaged `semantifold build [--check]`. Task 043 implements the language-neutral deterministic watch coordinator and `semantifold watch [--check]`; Task 044 proves its packed JavaScript/JSDoc-to-Java checked vertical slice. Task 045 remains the terminal all-text matrix.
|
|
6
6
|
|
|
7
7
|
The inspected baseline is `semantifold@0.7.0`, annotated tag `v0.7.0`, commit `8cd70c5a6c7de98df2d4a183d6555ad4f3d5ba5a`. At that revision:
|
|
8
8
|
|
|
@@ -11,31 +11,31 @@ The inspected baseline is `semantifold@0.7.0`, annotated tag `v0.7.0`, commit `8
|
|
|
11
11
|
- `discoverCanonicalToolchain` finds the configured `javac` and `java` executables.
|
|
12
12
|
- `runAcceptanceStages` materializes an artifact set in a temporary directory and runs caller-supplied exact argument arrays with bounded process execution.
|
|
13
13
|
- A bounded direct proof parsed the 2,648-byte JSDoc fixture `spec/fixtures/compatibility/program.js`, generated `Main.java`, compiled it with `javac 25.0.4`, executed it with Java 25.0.4, and observed the canonical output `compat\nbranch-ok!\npresent\nabsent\n7\n2\n3\n5\n4\n`.
|
|
14
|
-
- `package.json`
|
|
14
|
+
- `package.json` had no `bin` entry. The public API did not persist generated artifacts, load a project manifest, derive compiler arguments from a target, or watch source files.
|
|
15
15
|
- The only repository file-change watcher is a test helper; there is no product watch coordinator, incremental dependency graph, event coalescing policy, or long-lived compiler owner.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
That historical baseline proved **JavaScript/JSDoc → semantic IR → Java → `javac`** as a one-shot composition. Released `semantifold@0.9.0` supplies Task 038's public language-neutral `GeneratedArtifactPublisher`, immutable generation manifests, one atomic active pointer, pointer-once resolution, and journal-bounded recovery. Task 039 adds the package bin, project configuration, and one-shot CLI behavior; Task 040 productizes the generic plan/runner and Java compiler boundary; Task 041 adds PHP, Ruby, JavaScript, TypeScript, Kotlin/JVM, Python, and C# plans; Task 042 adds Go, C, C++, Rust, Swift, Dart, and Zig plans; Task 043 supplies generic watch coordination; and Task 044 supplies the packed credential-free watch proof and public example.
|
|
18
18
|
|
|
19
19
|
## Product outcome
|
|
20
20
|
|
|
21
|
-
A project can declare explicit source modules, one or more generated targets, one publisher-owned project publication root, target-relative generated/build projections
|
|
21
|
+
A project can declare explicit source modules, one or more generated targets, one publisher-owned project publication root, and target-relative generated/build projections. The one-shot CLI selects generation-only or all-target developer checking with `--check`. It can then run:
|
|
22
22
|
|
|
23
|
-
-
|
|
24
|
-
-
|
|
23
|
+
- the implemented one-shot `semantifold build`; or
|
|
24
|
+
- the implemented long-lived `semantifold watch`.
|
|
25
25
|
|
|
26
26
|
For the first end-to-end slice, changing a JSDoc-typed JavaScript source regenerates Java and compiles the staged candidate with `javac`. A successful cycle publishes one coherent generated-source/compiler-output generation through one active-generation pointer switch. A parse, semantic, generation, tool-discovery, compiler, or publication failure reports a located diagnostic, keeps the process alive in watch mode, and leaves the previous successful generation usable. A later valid edit recovers without restarting the watcher.
|
|
27
27
|
|
|
28
|
-
The architecture is target-neutral.
|
|
28
|
+
The architecture is target-neutral. All fifteen text targets supply target-owned plans. Every current source frontend participates through the existing parser/project APIs; the watcher never contains language syntax logic.
|
|
29
29
|
|
|
30
30
|
## Architecture boundaries
|
|
31
31
|
|
|
32
|
-
### Project manifest and loader
|
|
32
|
+
### Project manifest and loader (Task 039 implemented)
|
|
33
33
|
|
|
34
34
|
A versioned, strict manifest declares ordered source modules and target entries. Source language, module identity, entry identity, target language/role, one project publication root, and each target's generated/check subpaths inside an immutable project generation are explicit. These target paths are logical projections, not independently promoted filesystem roots. Version 1 uses explicit file paths rather than introducing a glob language or package-manager resolution.
|
|
35
35
|
|
|
36
|
-
The loader owns path normalization and rejects unknown fields, duplicate module/target identities, ambiguous target roles, source/publication overlap, publication roots outside the project root, colliding or nested target projections,
|
|
36
|
+
The loader owns path normalization and rejects unknown fields, duplicate module/target identities, ambiguous target roles, source/publication overlap, publication roots outside the project root, colliding or nested target projections, symlink/path traversal across the owned publication root, and registered backend capabilities whose required configuration version 1 cannot express. It returns an immutable project request and never parses language syntax.
|
|
37
37
|
|
|
38
|
-
### Snapshot builder
|
|
38
|
+
### Snapshot builder (Task 039 implemented for one-shot builds)
|
|
39
39
|
|
|
40
40
|
Each cycle reads a complete content snapshot of every declared source and the project manifest. File events are hints only. Before parsing, the coordinator re-reads and hashes the declared graph in stable order; it never assumes an event filename is complete or authoritative.
|
|
41
41
|
|
|
@@ -49,26 +49,40 @@ Frontends, semantic validation, linking, and backends remain pure with respect t
|
|
|
49
49
|
|
|
50
50
|
`GeneratedArtifactPublisher` stages one complete project candidate as a new immutable generation beneath a dedicated publisher-owned publication directory inside the canonical project root. Every target carries an explicit language-neutral role, and its generated artifacts, mappings, and optional validator/compiler outputs live in generation-relative subtrees on the same filesystem. The publisher validates paths, mappings, hashes, hard-link identities, complete generation inventory, collisions, ownership, and manifests before touching committed state. Its public contract and caller obligations are documented in [transactional generated-artifact publication](generated-artifact-publication.md).
|
|
51
51
|
|
|
52
|
-
When checking is enabled, target checks run against those staged generation subtrees. Only a fully generated and successfully checked project candidate may be published. The generation manifest is the explicit versioned authority for files the publisher created; it never authorizes mutation outside the publication root.
|
|
52
|
+
When checking is enabled, target checks run against those staged generation subtrees. Each checked invocation owns a fresh immutable candidate identity, including for an unchanged or reverted source snapshot, so it cannot reuse retained compiler output instead of executing the declared checks. Generation-only snapshots retain deterministic same-ID verification and reactivation. Only a fully generated and successfully checked project candidate may be published. The generation manifest is the explicit versioned authority for files the publisher created; it never authorizes mutation outside the publication root.
|
|
53
53
|
|
|
54
54
|
Publication commits exactly one small active-generation pointer by writing and syncing a sibling temporary pointer, atomically replacing the prior pointer on the same filesystem, and syncing the parent directory before reporting success. A host filesystem that cannot provide atomic same-directory regular-file replacement is rejected before publication; copying, truncating, or rewriting the live pointer in place is never a fallback. Readers resolve that pointer once and consume all generated/build paths from the referenced immutable generation. Configured generated-source and compiler-output names are logical projections returned from that resolved generation; they are never independent directories, symlinks, or manifests promoted one after another. The same rule covers every target in a multi-target cycle.
|
|
55
55
|
|
|
56
56
|
An interruption before the pointer replacement leaves the previous generation active; an interruption after it leaves either the old or new complete pointer durably recoverable, never a composite state. A recovery journal may finish cleanup of unpublished candidates and temporary pointer files, but it is not used to claim atomicity across multiple filesystem operations. Candidate and temporary-pointer parent directories are synchronized before the proving journal is removed and its directory synchronized. Publication never removes a committed generation, because a reader may already hold its resolved snapshot; committed-generation retention/garbage collection is a separate explicit policy. A failed candidate is removed without changing the active pointer.
|
|
57
57
|
|
|
58
|
-
### Target check-plan registry
|
|
58
|
+
### Target check-plan registry (Tasks 040–042 implemented)
|
|
59
59
|
|
|
60
|
-
The existing language registry remains authoritative for target identity, roles, declared acceptance stages, and required toolchain IDs.
|
|
60
|
+
The existing language registry remains authoritative for target identity, roles, declared acceptance stages, and required toolchain IDs. Its explicit immutable `check` capability distinguishes generation-only targets from Java plus PHP, Ruby, JavaScript, TypeScript, Kotlin/JVM, Python, and C# developer checks without claiming execution. The target-owned factory derives exact stage requests from a validated staged artifact set and its generation-scoped target source/build subtrees.
|
|
61
61
|
|
|
62
|
-
The generic runner owns process lifecycle, locale/timezone normalization, output capture, timeout/cancellation, and close
|
|
62
|
+
The generic runner validates immutable dense argv, complete artifact inputs, restore hashes, candidate-path ownership, exact discovered-tool environment bindings, nullable output ownership, and transient candidate directories before spawn. It owns process lifecycle, locale/timezone normalization, bounded output capture, timeout/cancellation, signal forwarding, first failure, close observation, and post-close transient cleanup. A target check plan owns filenames, exact argv, toolchain IDs, offline/cache policy, and which stages constitute a non-executing developer check. The builder and watcher do not switch on language IDs.
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
Java/`javac` compiles every staged `.java` artifact together with `-d` directed at the candidate build subtree and never invokes `java`. Task 041 implements the interpreted/managed cohort:
|
|
65
65
|
|
|
66
|
-
-
|
|
67
|
-
-
|
|
66
|
+
- PHP, Ruby, and JavaScript run real syntax checks once per generated language artifact;
|
|
67
|
+
- TypeScript type-checks the complete set with no emit and isolated type roots;
|
|
68
|
+
- Kotlin/JVM compiles all sources together to candidate-owned classes;
|
|
69
|
+
- Python produces deterministic checked-hash bytecode at an explicit candidate build path and never creates source-adjacent `__pycache__`;
|
|
70
|
+
- C# requires its exact producer-owned project, disables ancestor MSBuild props/targets, passes every staged `.cs` file in deterministic order, hashes project/lock restore inputs, restores from a local-only staged source into candidate-owned state, builds with `--no-restore`, and removes cache/home/intermediate state before publishing only `bin/` outputs.
|
|
68
71
|
|
|
69
|
-
|
|
72
|
+
Task 042 implements the remaining cohort:
|
|
70
73
|
|
|
71
|
-
|
|
74
|
+
- Go disables cgo, workspace/toolchain switching, VCS, and network resolution for its build, then vets read-only with isolated HOME/GOPATH/module/build/temp state.
|
|
75
|
+
- C and C++ compile every translation unit and link through the strict Clang C17 or C++20/libstdc++ `-O0` developer profile. Object/temp state is transient; `-O2` and ASan/UBSan remain explicit CI acceptance profiles rather than watcher branches.
|
|
76
|
+
- Rust accepts only the dependency-free generated Cargo manifest/lock, qualifies both Rustc and Cargo, binds Cargo's `RUSTC` to that exact discovered compiler, runs locked offline build/check with isolated Cargo home/target state, and removes that state before publication.
|
|
77
|
+
- Swift type-checks and compiles with exact driver mode and warnings as errors while isolating home/cache/temp state.
|
|
78
|
+
- Dart validates only the producer-owned dependency-free package/lock through an enforced offline dry run, compiles a native executable, verifies format, and analyzes fatally. The restore hash excludes ordinary source edits; `.dart_tool`, pub/home/temp state, and the absolute-source-URI-bearing native check output are transient.
|
|
79
|
+
- Zig accepts only the producer-owned standard-library-only project, builds Debug with isolated local/global caches and an owned transient prefix, then verifies canonical formatting. Multi-mode builds/tests remain explicit acceptance profiles.
|
|
80
|
+
|
|
81
|
+
None of these developer plans executes its generated program. A later validator does not hide an earlier declared compiler/linker output, and all candidate transient state is removed after child close on success, failure, timeout, or cancellation.
|
|
82
|
+
|
|
83
|
+
A watch check validates or compiles but does not execute generated application code by default. A content-identical reconciliation admits no cycle and therefore performs no restore. Every fresh C# candidate uses its declared project/lock hash, generation-specific SDK assets, and local-only package source; it reruns restore without network access because checked generations do not share mutable restore state.
|
|
84
|
+
|
|
85
|
+
### Watch coordinator (Task 043 implemented)
|
|
72
86
|
|
|
73
87
|
One lifecycle-aware class owns filesystem subscriptions, content snapshots, cycle state, the active checker child, reporting, and shutdown. Its state machine is:
|
|
74
88
|
|
|
@@ -85,11 +99,13 @@ any live state -- SIGINT/SIGTERM --> stopping --> stopped
|
|
|
85
99
|
|
|
86
100
|
`failed` means the last candidate failed; it does not discard the last successful output or terminate watch mode. A watcher event during `building`/`rebuilding` sets one dirty generation marker. The coordinator starts exactly one follow-up after the owned child closes. It never starts a retry while prior compiler work is still live.
|
|
87
101
|
|
|
88
|
-
Native filesystem events require a bounded reconciliation strategy because Node and TypeScript both document platform-dependent watcher behavior. Version 1 watches the explicit manifest/source files and
|
|
102
|
+
Native filesystem events require a bounded reconciliation strategy because Node and TypeScript both document platform-dependent watcher behavior. Version 1 watches the explicit manifest/source files and their distinct parent directories without recursive watching, filters publisher-owned parent events, re-scans the complete graph after each coalesced hint, supplements native events with a bounded reconciliation interval, switches wholly to polling when native subscription creation or a live watcher fails, and suppresses no-op cycles by content hash. Polling metadata is only a reconciliation hint, and unchanged invalid graphs do not emit repeated failed cycles. The publication root and every generated/build projection are rejected as sources and are never direct subscriptions, preventing publication feedback cycles.
|
|
103
|
+
|
|
104
|
+
The implemented pre-pointer currentness guard runs only after every target validator/checker has closed. It re-loads and hashes the complete graph; changed content rejects and cleans the stale staged candidate, while one dirty marker admits a single immediate latest-state follow-up. A later event in the narrow guard-to-pointer window cancels publication without cancelling a healthy checker earlier in the cycle.
|
|
89
105
|
|
|
90
106
|
### Reporting contract
|
|
91
107
|
|
|
92
|
-
|
|
108
|
+
Task 039 human output is concise and stable. Its machine-readable mode emits deterministic state records with project identity, cycle `1`, source snapshot hash, ordered target ID/role/results, exit status, and a structured diagnostic when present. Generation-only records deliberately report state rather than nondeterministic elapsed time. Task 040 checked-stage records add exact tool/process identity and lifecycle timing. Task 043 watch records add stable changed paths, cycle duration, succeeded/failed/recovered/superseded/cancelled classification, one terminal record per admitted cycle, and one separate watcher terminal. Task 044 adds the nonterminal `cycle-dirty` acknowledgement used to synchronize a controlled active-check burst with the coordinator's admitted follow-up ownership.
|
|
93
109
|
|
|
94
110
|
Exactly one terminal cycle record is emitted per cycle. Process exit is non-zero for failed one-shot builds, but ordinary watch-cycle failures keep the watcher process alive. Startup/configuration failure exits. Signal-driven shutdown forwards cancellation to an active owned child, waits for `close`, removes subscriptions and staging state, and exits once.
|
|
95
111
|
|
|
@@ -115,7 +131,7 @@ Exactly one terminal cycle record is emitted per cycle. Process exit is non-zero
|
|
|
115
131
|
- the same watcher/materializer/runner code handles every source/target pairing;
|
|
116
132
|
- acceptance uses a bounded matrix: all frontends and all text targets are covered, with the JavaScript/JSDoc-to-Java path plus representative cross-family paths, not a quadratic promise that every semantic feature works for every pair.
|
|
117
133
|
|
|
118
|
-
Binary and application targets use the same generation watcher only after explicit target policy is defined. Browser Wasm can validate/instantiate in its own lane. Android and Flutter checks are heavier platform builds and must be opt-in rather than an automatic keystroke default. iOS remains
|
|
134
|
+
Binary and application targets use the same generation watcher only after explicit target policy is defined. Browser Wasm can validate/instantiate in its own lane. Android and Flutter checks are heavier platform builds and must be opt-in rather than an automatic keystroke default. Direct public iOS generation remains available with explicit configuration, but Task 039 manifest version 1 cannot express that configuration and rejects iOS targets; Apple/Xcode acceptance remains separately deferred. This roadmap does not reopen Tasks 026 or 027.
|
|
119
135
|
|
|
120
136
|
## Test strategy
|
|
121
137
|
|
|
@@ -147,7 +163,7 @@ Binary and application targets use the same generation watcher only after explic
|
|
|
147
163
|
046 later binary/application policies
|
|
148
164
|
```
|
|
149
165
|
|
|
150
|
-
|
|
166
|
+
Tasks 038–041 and 043–044 are the implemented publication, one-shot project-build, Java plus interpreted/managed checks, watch-orchestration foundation, and first packed checked slice. Tasks 042 and 045 remain the selected text-language check/watch delivery chain, with Task 045 as its single terminal acceptance task. Task 046 is a non-blocking later extension.
|
|
151
167
|
|
|
152
168
|
## Non-goals
|
|
153
169
|
|
package/docs/zig.md
CHANGED
|
@@ -26,6 +26,8 @@ Strings are immutable `[]const u8`. Literals borrow static storage; concatenatio
|
|
|
26
26
|
|
|
27
27
|
`build.zig` exposes only Zig's standard optimization option and the host target. Acceptance copies validated artifacts to a fresh temporary project, uses distinct empty local/global caches per mode, blocks proxy/package-fetch variables, runs `zig fmt --check src/main.zig build.zig`, `zig build test`, `zig build`, and the installed executable in Debug, ReleaseSafe, and ReleaseFast, and verifies that input artifact hashes never change. Cross-compilation and package dependencies are outside this profile.
|
|
28
28
|
|
|
29
|
+
The registered Task 042 developer plan accepts only that exact standard-library-only `build.zig` and generated Zig sources. It runs the Debug project build with generation-owned local/global caches and `--prefix`, then `zig fmt --check` over the complete staged set. HOME, TMPDIR, both caches, and the absolute-root-bearing Debug output prefix are removed after close, so no executable leaks or is published. `zig build test` plus build/run in Debug, ReleaseSafe, and ReleaseFast remain explicit acceptance/TensorBuzz profiles rather than automatic watcher branches.
|
|
30
|
+
|
|
29
31
|
## Provenance and diagnostics
|
|
30
32
|
|
|
31
33
|
Function, parameter, local, type, assignment, operator/helper, callee, argument, literal, return, condition, output, and entry-statement occurrences retain exact or anchored semantic provenance in `src/main.zig`. The runtime, arena, output helpers, punctuation, ordered-region markers and signatures, typed ordering temporaries, conditional-right-hand plumbing, necessary unused/unmutated binding scaffolds, and entry shell are synthetic with related semantic origins. `build.zig` has artifact-level synthetic configuration provenance. The embedded Source Map v3 names `src/main.zig`; Zig source-map directives and alternate filenames are rejected.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "SemantifoldProject",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"id": "jsdoc-java-watch",
|
|
5
|
+
"publicationRoot": ".semantifold",
|
|
6
|
+
"sources": [
|
|
7
|
+
{
|
|
8
|
+
"id": "main",
|
|
9
|
+
"path": "src/main.js",
|
|
10
|
+
"language": "javascript",
|
|
11
|
+
"entry": true
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"targets": [
|
|
15
|
+
{
|
|
16
|
+
"id": "java-main",
|
|
17
|
+
"language": "java",
|
|
18
|
+
"role": "text",
|
|
19
|
+
"sourceProjection": "targets/java/source",
|
|
20
|
+
"buildProjection": "targets/java/classes"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {number} left
|
|
3
|
+
* @param {number} right
|
|
4
|
+
* @returns {number}
|
|
5
|
+
*/
|
|
6
|
+
function add(left, right) {
|
|
7
|
+
return left + right
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {boolean} enabled
|
|
12
|
+
* @returns {string}
|
|
13
|
+
*/
|
|
14
|
+
function label(enabled) {
|
|
15
|
+
if (enabled) return "enabled"
|
|
16
|
+
else return "disabled"
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
console.log("task-044")
|
|
20
|
+
console.log(add(2, 3))
|
|
21
|
+
console.log(label(true))
|
package/index.js
CHANGED
|
@@ -17,6 +17,14 @@ export {createCapabilityAuthority} from "./src/semantic/capabilities.js"
|
|
|
17
17
|
export {languageCapabilities, supportedLanguages} from "./src/language-registry.js"
|
|
18
18
|
export {createGeneratedArtifactSet} from "./src/artifacts.js"
|
|
19
19
|
export {GeneratedArtifactPublisher} from "./src/publication.js"
|
|
20
|
+
export {ProjectManifestLoader, SemantifoldProject} from "./src/project-manifest.js"
|
|
21
|
+
export {ProjectSnapshot, ProjectSnapshotBuilder} from "./src/project-snapshot.js"
|
|
22
|
+
export {ProjectBuilder} from "./src/project-build.js"
|
|
23
|
+
export {parseSemantifoldCliArguments, SemantifoldCli} from "./src/project-cli.js"
|
|
24
|
+
export {ProjectBuildReporter} from "./src/project-reporter.js"
|
|
25
|
+
export {ProjectWatchCoordinator} from "./src/project-watch.js"
|
|
26
|
+
export {ProjectWatchReporter} from "./src/project-watch-reporter.js"
|
|
27
|
+
export {createTargetCheckPlan, TargetCheckRunner} from "./src/target-check.js"
|
|
20
28
|
export {createStdlibContractRegistry, listStdlibModules, resolveStdlibModule} from "./src/semantic/stdlib.js"
|
|
21
29
|
export {createStdlibProviderRegistry, listStdlibProviders} from "./src/stdlib-providers.js"
|
|
22
30
|
export {negotiateStdlibProviders} from "./src/stdlib-negotiation.js"
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "semantifold",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Language-neutral semantic code analysis, transformation, generation, and execution toolkit",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "build/index.js",
|
|
7
7
|
"types": "build/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"semantifold": "bin/semantifold.js"
|
|
10
|
+
},
|
|
8
11
|
"exports": {
|
|
9
12
|
".": {
|
|
10
13
|
"types": "./build/index.d.ts",
|
|
@@ -13,7 +16,9 @@
|
|
|
13
16
|
},
|
|
14
17
|
"files": [
|
|
15
18
|
"build/**",
|
|
19
|
+
"bin/**",
|
|
16
20
|
"docs/**",
|
|
21
|
+
"examples/**",
|
|
17
22
|
"index.js",
|
|
18
23
|
"LICENSE",
|
|
19
24
|
"README.md",
|
package/src/artifact-path.js
CHANGED
|
@@ -52,18 +52,47 @@ export function portableArtifactPathKey(value) {
|
|
|
52
52
|
return value.toLowerCase()
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Produces a deterministic case-fold comparison key for a validated source path.
|
|
57
|
+
* @param {string} value - Safe relative POSIX source path.
|
|
58
|
+
* @returns {string} Unicode case-fold comparison key.
|
|
59
|
+
*/
|
|
60
|
+
export function portableSourcePathKey(value) {
|
|
61
|
+
return value.toLowerCase()
|
|
62
|
+
}
|
|
63
|
+
|
|
55
64
|
/**
|
|
56
65
|
* Finds the first unsafe, duplicate, portable case-fold, or file/directory-prefix conflict.
|
|
57
66
|
* @param {readonly string[]} paths - Ordered candidate artifact paths.
|
|
58
67
|
* @returns {{kind: "case-fold" | "duplicate" | "prefix" | "unsafe", path: string, other?: string} | null} First conflict.
|
|
59
68
|
*/
|
|
60
69
|
export function findPortableArtifactPathConflict(paths) {
|
|
70
|
+
return findPortablePathConflict(paths, isSafeArtifactPath, portableArtifactPathKey)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Finds the first unsafe, duplicate, portable case-fold, or file/directory-prefix source conflict.
|
|
75
|
+
* @param {readonly string[]} paths - Ordered candidate source paths.
|
|
76
|
+
* @returns {{kind: "case-fold" | "duplicate" | "prefix" | "unsafe", path: string, other?: string} | null} First conflict.
|
|
77
|
+
*/
|
|
78
|
+
export function findPortableSourcePathConflict(paths) {
|
|
79
|
+
return findPortablePathConflict(paths, isSafeSourcePath, portableSourcePathKey)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Compares paths inside one explicitly selected validation domain.
|
|
84
|
+
* @param {readonly string[]} paths - Ordered candidate paths.
|
|
85
|
+
* @param {(value: unknown) => boolean} isSafe - Domain-specific path validator.
|
|
86
|
+
* @param {(value: string) => string} comparisonKey - Domain-specific portable comparison key.
|
|
87
|
+
* @returns {{kind: "case-fold" | "duplicate" | "prefix" | "unsafe", path: string, other?: string} | null} First conflict.
|
|
88
|
+
*/
|
|
89
|
+
function findPortablePathConflict(paths, isSafe, comparisonKey) {
|
|
61
90
|
/** @type {{key: string, path: string}[]} */
|
|
62
91
|
const accepted = []
|
|
63
92
|
|
|
64
93
|
for (const path of paths) {
|
|
65
|
-
if (!
|
|
66
|
-
const key =
|
|
94
|
+
if (!isSafe(path)) return {kind: "unsafe", path: String(path)}
|
|
95
|
+
const key = comparisonKey(path)
|
|
67
96
|
|
|
68
97
|
for (const previous of accepted) {
|
|
69
98
|
if (path == previous.path) return {kind: "duplicate", other: previous.path, path}
|
|
@@ -0,0 +1,80 @@
|
|
|
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 {cRuntimeHeader} from "./c-runtime.js"
|
|
15
|
+
|
|
16
|
+
const compilerFlags = Object.freeze([
|
|
17
|
+
"--no-default-config", "-std=c17", "-Wall", "-Wextra", "-Werror", "-pedantic-errors", "-Wconversion",
|
|
18
|
+
"-Wsign-conversion", "-Wshadow", "-Wstrict-prototypes", "-Wmissing-prototypes", "-Wformat=2", "-ftrapv",
|
|
19
|
+
"-finput-charset=UTF-8", "-fexec-charset=UTF-8", "-fno-color-diagnostics", "-O0"
|
|
20
|
+
])
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Constructs C's strict Clang C17 compile/link plan.
|
|
24
|
+
* @param {import("../language-registry.js").TargetCheckPlanContext} context - Validated candidate context.
|
|
25
|
+
* @returns {import("../semantic/types.js").TargetCheckPlan} Immutable C plan.
|
|
26
|
+
*/
|
|
27
|
+
export function createCCheckPlan(context) {
|
|
28
|
+
const tool = checkTool(context, "clang", "c")
|
|
29
|
+
const artifacts = checkArtifacts(context, artifact => artifact.path.endsWith(".c") || artifact.path.endsWith(".h"),
|
|
30
|
+
"c", "only staged C translation units and headers")
|
|
31
|
+
const sources = artifacts.filter(artifact => artifact.endsWith(".c"))
|
|
32
|
+
const headers = artifacts.filter(artifact => artifact.endsWith(".h"))
|
|
33
|
+
const support = context.artifacts.artifacts.filter(artifact => artifact.path == "semantifold_runtime.h")
|
|
34
|
+
|
|
35
|
+
if (artifacts.length != 2 || sources.length != 1 || sources[0] != path.join(context.sourcePath, "program.c") ||
|
|
36
|
+
headers.length != 1 || support.length != 1 || support[0].contentKind != "text" || support[0].role != "support" ||
|
|
37
|
+
support[0].content != cRuntimeHeader) {
|
|
38
|
+
throw new SemantifoldDiagnostic({code: "INVALID_TARGET_CHECK_PLAN", language: "c",
|
|
39
|
+
message: "C developer checks require the exact producer-owned translation unit and support header."})
|
|
40
|
+
}
|
|
41
|
+
const objects = path.join(context.buildPath, "objects")
|
|
42
|
+
const temporary = path.join(context.buildPath, "tmp")
|
|
43
|
+
const environment = {TMPDIR: temporary}
|
|
44
|
+
const environmentPaths = [environmentPath("TMPDIR", "build")]
|
|
45
|
+
const objectPaths = sources.map((_, index) => path.join(objects, `${String(index).padStart(6, "0")}.o`))
|
|
46
|
+
const stages = sources.map((source, index) => {
|
|
47
|
+
const argv = [...compilerFlags, "-c", source, "-o", objectPaths[index]]
|
|
48
|
+
|
|
49
|
+
return checkStage({
|
|
50
|
+
argv,
|
|
51
|
+
cwd: context.sourcePath,
|
|
52
|
+
environment,
|
|
53
|
+
environmentPaths,
|
|
54
|
+
inputs: [source, ...headers],
|
|
55
|
+
output: null,
|
|
56
|
+
pathArguments: [pathArgument(argv.length - 3, "source"), pathArgument(argv.length - 1, "build")],
|
|
57
|
+
stage: /** @type {const} */ ("compile"),
|
|
58
|
+
tool,
|
|
59
|
+
transientPaths: [objects]
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
const binary = path.join(context.buildPath, "semantifold-c")
|
|
63
|
+
const linkArgv = ["--no-default-config", "-O0", ...objectPaths, "-o", binary]
|
|
64
|
+
|
|
65
|
+
stages.push(checkStage({
|
|
66
|
+
argv: linkArgv,
|
|
67
|
+
cwd: context.sourcePath,
|
|
68
|
+
environment,
|
|
69
|
+
environmentPaths,
|
|
70
|
+
inputs: objectPaths,
|
|
71
|
+
output: checkOutput(context.buildPath, "application/x-executable", "linker-output"),
|
|
72
|
+
pathArguments: [...objectPaths.map((_, index) => pathArgument(index + 2, "build")),
|
|
73
|
+
pathArgument(linkArgv.length - 1, "build")],
|
|
74
|
+
stage: "link",
|
|
75
|
+
tool,
|
|
76
|
+
transientPaths: [objects]
|
|
77
|
+
}))
|
|
78
|
+
|
|
79
|
+
return checkPlan(context, "c", artifacts, stages)
|
|
80
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
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
|
+
* Resolves one target-declared discovered tool from immutable plan context.
|
|
9
|
+
* @param {Readonly<{tools: readonly import("../semantic/types.js").DiscoveredToolchain[]}>} context - Plan context.
|
|
10
|
+
* @param {string} id - Declared toolchain identity.
|
|
11
|
+
* @param {string} target - Target diagnostic identity.
|
|
12
|
+
* @returns {import("../semantic/types.js").DiscoveredToolchain} Exact tool.
|
|
13
|
+
*/
|
|
14
|
+
export function checkTool(context, id, target) {
|
|
15
|
+
const tool = context.tools.find(candidate => candidate.id == id)
|
|
16
|
+
|
|
17
|
+
if (!tool) {
|
|
18
|
+
throw new SemantifoldDiagnostic({
|
|
19
|
+
code: "INVALID_TARGET_CHECK_PLAN",
|
|
20
|
+
language: target,
|
|
21
|
+
message: `Target '${target}' developer checks require the declared '${id}' toolchain.`
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return tool
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Resolves all staged artifacts matching one target-owned predicate.
|
|
30
|
+
* @param {Readonly<{artifacts: import("../semantic/types.js").GeneratedArtifactSet, sourcePath: string}>} context - Plan context.
|
|
31
|
+
* @param {(artifact: import("../semantic/types.js").GeneratedSetArtifact) => boolean} accepts - Target-owned artifact predicate.
|
|
32
|
+
* @param {string} target - Target diagnostic identity.
|
|
33
|
+
* @param {string} description - Required artifact description.
|
|
34
|
+
* @returns {readonly string[]} Ordered absolute artifact paths.
|
|
35
|
+
*/
|
|
36
|
+
export function checkArtifacts(context, accepts, target, description) {
|
|
37
|
+
const accepted = context.artifacts.artifacts.filter(accepts)
|
|
38
|
+
|
|
39
|
+
if (accepted.length == 0 || accepted.length != context.artifacts.artifacts.length) {
|
|
40
|
+
throw new SemantifoldDiagnostic({
|
|
41
|
+
code: "INVALID_TARGET_CHECK_PLAN",
|
|
42
|
+
language: target,
|
|
43
|
+
message: `Target '${target}' developer checks require ${description}.`
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return Object.freeze(accepted.map(artifact => path.join(context.sourcePath, artifact.path))
|
|
48
|
+
.sort((left, right) => left.localeCompare(right, "en")))
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Freezes one closed target-check stage request.
|
|
53
|
+
* @param {object} input - Complete stage data.
|
|
54
|
+
* @param {readonly string[]} input.argv - Exact argv.
|
|
55
|
+
* @param {string} input.cwd - Candidate-owned working directory.
|
|
56
|
+
* @param {Readonly<Record<string, string | undefined>>} [input.environment] - Target-owned environment additions.
|
|
57
|
+
* @param {readonly import("../semantic/types.js").TargetCheckEnvironmentPath[]} [input.environmentPaths] - Owned environment paths.
|
|
58
|
+
* @param {string | null} [input.inputHash] - Restore-input hash when applicable.
|
|
59
|
+
* @param {readonly string[]} input.inputs - Exact staged inputs read by the tool.
|
|
60
|
+
* @param {import("../semantic/types.js").TargetCheckOutputOwnership | null} input.output - Produced build ownership.
|
|
61
|
+
* @param {readonly import("../semantic/types.js").TargetCheckPathArgument[]} input.pathArguments - Owned argv paths.
|
|
62
|
+
* @param {import("../semantic/types.js").AcceptanceStage} input.stage - Stage identity.
|
|
63
|
+
* @param {import("../semantic/types.js").DiscoveredToolchain} input.tool - Exact tool.
|
|
64
|
+
* @param {readonly string[]} [input.transientPaths] - Owned cache/intermediate directories.
|
|
65
|
+
* @returns {import("../semantic/types.js").TargetCheckStageRequest} Immutable stage.
|
|
66
|
+
*/
|
|
67
|
+
export function checkStage(input) {
|
|
68
|
+
return Object.freeze({
|
|
69
|
+
argv: Object.freeze([...input.argv]),
|
|
70
|
+
cwd: input.cwd,
|
|
71
|
+
environment: deterministicEnvironment(input.environment ?? {}),
|
|
72
|
+
environmentPaths: Object.freeze([...(input.environmentPaths ?? [])]),
|
|
73
|
+
executable: input.tool.executable,
|
|
74
|
+
inputHash: input.inputHash ?? null,
|
|
75
|
+
inputs: Object.freeze([...input.inputs]),
|
|
76
|
+
output: input.output,
|
|
77
|
+
pathArguments: Object.freeze([...input.pathArguments]),
|
|
78
|
+
stage: input.stage,
|
|
79
|
+
tool: input.tool,
|
|
80
|
+
transientPaths: Object.freeze([...(input.transientPaths ?? [])])
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Freezes one closed target-owned plan.
|
|
86
|
+
* @param {Readonly<{buildPath: string, projectId: string, sourcePath: string, targetId: string}>} context - Plan context.
|
|
87
|
+
* @param {string} target - Target identity.
|
|
88
|
+
* @param {readonly string[]} artifactPaths - Complete staged artifact vector.
|
|
89
|
+
* @param {readonly import("../semantic/types.js").TargetCheckStageRequest[]} stages - Ordered stages.
|
|
90
|
+
* @returns {import("../semantic/types.js").TargetCheckPlan} Immutable plan.
|
|
91
|
+
*/
|
|
92
|
+
export function checkPlan(context, target, artifactPaths, stages) {
|
|
93
|
+
return Object.freeze({
|
|
94
|
+
artifactPaths,
|
|
95
|
+
buildPath: context.buildPath,
|
|
96
|
+
mode: /** @type {const} */ ("developer-check"),
|
|
97
|
+
projectId: context.projectId,
|
|
98
|
+
schema: /** @type {const} */ ("SemantifoldTargetCheckPlan"),
|
|
99
|
+
sourcePath: context.sourcePath,
|
|
100
|
+
stages: Object.freeze([...stages]),
|
|
101
|
+
target,
|
|
102
|
+
targetId: context.targetId,
|
|
103
|
+
version: /** @type {const} */ (1)
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Freezes one owned argv-path declaration.
|
|
109
|
+
* @param {number} index - Exact argv index.
|
|
110
|
+
* @param {"source" | "build"} ownership - Owning candidate subtree.
|
|
111
|
+
* @param {string} [prefix] - Optional non-path argument prefix.
|
|
112
|
+
* @returns {import("../semantic/types.js").TargetCheckPathArgument} Immutable declaration.
|
|
113
|
+
*/
|
|
114
|
+
export function pathArgument(index, ownership, prefix) {
|
|
115
|
+
return Object.freeze({index, ownership, ...(prefix === undefined ? {} : {prefix})})
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Freezes one owned environment-directory declaration.
|
|
120
|
+
* @param {string} name - Exact environment variable.
|
|
121
|
+
* @param {"source" | "build"} ownership - Owning candidate subtree.
|
|
122
|
+
* @returns {import("../semantic/types.js").TargetCheckEnvironmentPath} Immutable declaration.
|
|
123
|
+
*/
|
|
124
|
+
export function environmentPath(name, ownership) {
|
|
125
|
+
return Object.freeze({name, ownership})
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Freezes one exact tool-executable environment binding.
|
|
130
|
+
* @param {string} name - Exact environment variable.
|
|
131
|
+
* @param {import("../semantic/types.js").DiscoveredToolchain} tool - Exact discovered tool.
|
|
132
|
+
* @returns {import("../semantic/types.js").TargetCheckEnvironmentPath} Immutable declaration.
|
|
133
|
+
*/
|
|
134
|
+
export function environmentTool(name, tool) {
|
|
135
|
+
return Object.freeze({name, ownership: /** @type {const} */ ("tool"), tool})
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Freezes build-output ownership metadata.
|
|
140
|
+
* @param {string} buildPath - Exact candidate build root.
|
|
141
|
+
* @param {string} mediaType - Output media type.
|
|
142
|
+
* @param {string} role - Language-neutral output role.
|
|
143
|
+
* @returns {import("../semantic/types.js").TargetCheckOutputOwnership} Immutable ownership.
|
|
144
|
+
*/
|
|
145
|
+
export function checkOutput(buildPath, mediaType, role) {
|
|
146
|
+
return Object.freeze({mediaType, ownership: /** @type {const} */ ("build"), path: buildPath, role})
|
|
147
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
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
|
+
const compilerFlags = Object.freeze([
|
|
16
|
+
"--no-default-config", "--driver-mode=g++", "-std=c++20", "-stdlib=libstdc++", "-Wall", "-Wextra", "-Werror",
|
|
17
|
+
"-pedantic-errors", "-Wconversion", "-Wsign-conversion", "-Wshadow", "-Wformat=2", "-fno-exceptions", "-fno-rtti",
|
|
18
|
+
"-ftrapv", "-finput-charset=UTF-8", "-fexec-charset=UTF-8", "-fno-color-diagnostics", "-O0"
|
|
19
|
+
])
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Constructs C++'s strict Clang C++20/libstdc++ compile/link plan.
|
|
23
|
+
* @param {import("../language-registry.js").TargetCheckPlanContext} context - Validated candidate context.
|
|
24
|
+
* @returns {import("../semantic/types.js").TargetCheckPlan} Immutable C++ plan.
|
|
25
|
+
*/
|
|
26
|
+
export function createCppCheckPlan(context) {
|
|
27
|
+
const tool = checkTool(context, "clangpp", "cpp")
|
|
28
|
+
const artifacts = checkArtifacts(context, artifact => artifact.path.endsWith(".cpp"), "cpp", "only staged '.cpp' translation units")
|
|
29
|
+
|
|
30
|
+
if (artifacts.length != 1 || artifacts[0] != path.join(context.sourcePath, "program.cpp")) {
|
|
31
|
+
throw new SemantifoldDiagnostic({code: "INVALID_TARGET_CHECK_PLAN", language: "cpp",
|
|
32
|
+
message: "C++ developer checks require the exact producer-owned 'program.cpp' translation unit."})
|
|
33
|
+
}
|
|
34
|
+
const objects = path.join(context.buildPath, "objects")
|
|
35
|
+
const temporary = path.join(context.buildPath, "tmp")
|
|
36
|
+
const environment = {TMPDIR: temporary}
|
|
37
|
+
const environmentPaths = [environmentPath("TMPDIR", "build")]
|
|
38
|
+
const objectPaths = artifacts.map((_, index) => path.join(objects, `${String(index).padStart(6, "0")}.o`))
|
|
39
|
+
const stages = artifacts.map((source, index) => {
|
|
40
|
+
const argv = [...compilerFlags, "-c", source, "-o", objectPaths[index]]
|
|
41
|
+
|
|
42
|
+
return checkStage({
|
|
43
|
+
argv,
|
|
44
|
+
cwd: context.sourcePath,
|
|
45
|
+
environment,
|
|
46
|
+
environmentPaths,
|
|
47
|
+
inputs: [source],
|
|
48
|
+
output: null,
|
|
49
|
+
pathArguments: [pathArgument(argv.length - 3, "source"), pathArgument(argv.length - 1, "build")],
|
|
50
|
+
stage: /** @type {const} */ ("compile"),
|
|
51
|
+
tool,
|
|
52
|
+
transientPaths: [objects]
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
const binary = path.join(context.buildPath, "semantifold-cpp")
|
|
56
|
+
const linkArgv = ["--no-default-config", "--driver-mode=g++", "-stdlib=libstdc++", "-O0", ...objectPaths, "-o", binary]
|
|
57
|
+
|
|
58
|
+
stages.push(checkStage({
|
|
59
|
+
argv: linkArgv,
|
|
60
|
+
cwd: context.sourcePath,
|
|
61
|
+
environment,
|
|
62
|
+
environmentPaths,
|
|
63
|
+
inputs: objectPaths,
|
|
64
|
+
output: checkOutput(context.buildPath, "application/x-executable", "linker-output"),
|
|
65
|
+
pathArguments: [...objectPaths.map((_, index) => pathArgument(index + 4, "build")),
|
|
66
|
+
pathArgument(linkArgv.length - 1, "build")],
|
|
67
|
+
stage: "link",
|
|
68
|
+
tool,
|
|
69
|
+
transientPaths: [objects]
|
|
70
|
+
}))
|
|
71
|
+
|
|
72
|
+
return checkPlan(context, "cpp", artifacts, stages)
|
|
73
|
+
}
|