@sprig-and-prose/sprig 0.6.1 → 0.7.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/CHANGELOG.md +28 -0
- package/dist/scene-compiler.d.ts.map +1 -1
- package/dist/scene-compiler.js +35 -4
- package/dist/scene-compiler.js.map +1 -1
- package/package.json +1 -1
- package/src/scene-compiler.ts +42 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @sprig-and-prose/sprig
|
|
2
2
|
|
|
3
|
+
## 0.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 4a9cd76: **sprig-scenes (scene compiler):**
|
|
8
|
+
|
|
9
|
+
- **Shape groups:** Only treat `group` as a group declaration when it is followed by an identifier (group name). `group { string }` is now parsed as a top-level field named `group` of type string.
|
|
10
|
+
- **Field order:** Manifest fields are emitted in definition order (group fields first in group order, then top-level fields).
|
|
11
|
+
- **Validation:** A field may only define a single type. Error when two or more types appear in a field block, with message naming the field.
|
|
12
|
+
- **Validation:** Error when a field block is empty (no type), with message naming the field (e.g. "Field 'id' does not contain any type block...").
|
|
13
|
+
- **Errors:** `parseFieldBlock` accepts an optional field name for clearer, field-named error messages.
|
|
14
|
+
|
|
15
|
+
**sprig (CLI):**
|
|
16
|
+
|
|
17
|
+
- **Invalid scene output:** When a scene fails to compile, write `<base>.error.txt` in the output directory with the error message(s) and a location line: ` at <scene-name>` when the scene name can be parsed from source, or ` in <filename>` otherwise. Enables testing invalid prose by asserting on generated error files.
|
|
18
|
+
- Remove any existing `.error.txt` for a scene when that scene later compiles successfully.
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- Updated dependencies [4a9cd76]
|
|
23
|
+
- @sprig-and-prose/sprig-scenes@0.3.0
|
|
24
|
+
|
|
25
|
+
## 0.6.2
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- 0018e7d: Patch release for compatibility with updated scenes.
|
|
30
|
+
|
|
3
31
|
## 0.6.1
|
|
4
32
|
|
|
5
33
|
### Patch Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scene-compiler.d.ts","sourceRoot":"","sources":["../src/scene-compiler.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC7F;
|
|
1
|
+
{"version":3,"file":"scene-compiler.d.ts","sourceRoot":"","sources":["../src/scene-compiler.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC7F;AA2CD;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,kBAAkB,CAAC,CAwG7B"}
|
package/dist/scene-compiler.js
CHANGED
|
@@ -1,10 +1,29 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync, mkdirSync, renameSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, renameSync, unlinkSync } from "node:fs";
|
|
2
|
+
import { join, basename } from "node:path";
|
|
3
3
|
import { execSync } from "node:child_process";
|
|
4
4
|
import fg from "fast-glob";
|
|
5
5
|
// Import directly from compile_scene to avoid scene-engine dependency
|
|
6
6
|
// @ts-expect-error - sprig-scenes doesn't have full TypeScript types
|
|
7
7
|
import { compileSceneFromText } from "@sprig-and-prose/sprig-scenes/compiler/compile_scene";
|
|
8
|
+
/** Base name for output files derived from scene prose path (e.g. 05-group.scene.prose → 05-group). */
|
|
9
|
+
function sceneFileBaseName(sceneFile) {
|
|
10
|
+
return basename(sceneFile).replace(/\.scene\.prose$/i, "") || "scene";
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Write compile errors to <base>.error.txt in outputDir.
|
|
14
|
+
* One line per error, then " at <scene-name>" if scene name was parsed from source, else " in <filename>".
|
|
15
|
+
*/
|
|
16
|
+
function writeSceneErrors(outputDir, sceneFile, errors, sourceText) {
|
|
17
|
+
const base = sceneFileBaseName(sceneFile);
|
|
18
|
+
const sceneNameMatch = sourceText.match(/\bscene\s+([A-Za-z_][A-Za-z0-9_]*)\s*\{/);
|
|
19
|
+
const locationLine = sceneNameMatch
|
|
20
|
+
? " at " + sceneNameMatch[1] + "\n"
|
|
21
|
+
: " in " + base + "\n";
|
|
22
|
+
const errorPath = join(outputDir, `${base}.error.txt`);
|
|
23
|
+
const errorBlock = errors.join("\n").trim() + (errors.length ? "\n" : "");
|
|
24
|
+
const content = errorBlock + locationLine;
|
|
25
|
+
writeFileSync(errorPath, content, "utf-8");
|
|
26
|
+
}
|
|
8
27
|
/**
|
|
9
28
|
* Generate manifestId: git:<sha> if available, else time:<iso>
|
|
10
29
|
*/
|
|
@@ -55,15 +74,18 @@ export async function compileScenes(universeRoot, outputDir) {
|
|
|
55
74
|
const manifestId = generateManifestId();
|
|
56
75
|
// Compile each scene
|
|
57
76
|
for (const sceneFile of sceneFiles) {
|
|
77
|
+
let sourceText = "";
|
|
58
78
|
try {
|
|
59
|
-
|
|
79
|
+
sourceText = readFileSync(sceneFile, "utf-8");
|
|
60
80
|
const manifest = compileSceneFromText(sourceText);
|
|
61
81
|
if (!manifest || !manifest.sceneName) {
|
|
82
|
+
const message = "Failed to compile scene: no sceneName found";
|
|
62
83
|
diagnostics.push({
|
|
63
84
|
severity: "error",
|
|
64
|
-
message
|
|
85
|
+
message,
|
|
65
86
|
source: sceneFile,
|
|
66
87
|
});
|
|
88
|
+
writeSceneErrors(outputDir, sceneFile, [message], sourceText);
|
|
67
89
|
continue;
|
|
68
90
|
}
|
|
69
91
|
// Inject metadata
|
|
@@ -80,6 +102,14 @@ export async function compileScenes(universeRoot, outputDir) {
|
|
|
80
102
|
const json = JSON.stringify(manifestWithMeta, null, 2);
|
|
81
103
|
writeFileSync(tempPath, json, "utf-8");
|
|
82
104
|
renameSync(tempPath, outputPath);
|
|
105
|
+
// Remove any prior .error.txt for this scene (same source file base name)
|
|
106
|
+
const errorPath = join(outputDir, `${sceneFileBaseName(sceneFile)}.error.txt`);
|
|
107
|
+
try {
|
|
108
|
+
unlinkSync(errorPath);
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
// ignore if missing
|
|
112
|
+
}
|
|
83
113
|
compiledScenes.push(manifest.sceneName);
|
|
84
114
|
}
|
|
85
115
|
catch (error) {
|
|
@@ -89,6 +119,7 @@ export async function compileScenes(universeRoot, outputDir) {
|
|
|
89
119
|
message: `Scene compile failed: ${message}`,
|
|
90
120
|
source: sceneFile,
|
|
91
121
|
});
|
|
122
|
+
writeSceneErrors(outputDir, sceneFile, [message], sourceText);
|
|
92
123
|
}
|
|
93
124
|
}
|
|
94
125
|
const hasErrors = diagnostics.some((d) => d.severity === "error");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scene-compiler.js","sourceRoot":"","sources":["../src/scene-compiler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"scene-compiler.js","sourceRoot":"","sources":["../src/scene-compiler.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/scene-compiler.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync, mkdirSync, renameSync } from "node:fs";
|
|
2
|
-
import { join,
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, renameSync, unlinkSync } from "node:fs";
|
|
2
|
+
import { join, basename } from "node:path";
|
|
3
3
|
import { execSync } from "node:child_process";
|
|
4
4
|
import fg from "fast-glob";
|
|
5
5
|
// Import directly from compile_scene to avoid scene-engine dependency
|
|
@@ -12,6 +12,32 @@ export interface SceneCompileResult {
|
|
|
12
12
|
diagnostics: Array<{ severity: string; message: string; source?: unknown; scene?: string }>;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/** Base name for output files derived from scene prose path (e.g. 05-group.scene.prose → 05-group). */
|
|
16
|
+
function sceneFileBaseName(sceneFile: string): string {
|
|
17
|
+
return basename(sceneFile).replace(/\.scene\.prose$/i, "") || "scene";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Write compile errors to <base>.error.txt in outputDir.
|
|
22
|
+
* One line per error, then " at <scene-name>" if scene name was parsed from source, else " in <filename>".
|
|
23
|
+
*/
|
|
24
|
+
function writeSceneErrors(
|
|
25
|
+
outputDir: string,
|
|
26
|
+
sceneFile: string,
|
|
27
|
+
errors: string[],
|
|
28
|
+
sourceText: string,
|
|
29
|
+
): void {
|
|
30
|
+
const base = sceneFileBaseName(sceneFile);
|
|
31
|
+
const sceneNameMatch = sourceText.match(/\bscene\s+([A-Za-z_][A-Za-z0-9_]*)\s*\{/);
|
|
32
|
+
const locationLine = sceneNameMatch
|
|
33
|
+
? " at " + sceneNameMatch[1] + "\n"
|
|
34
|
+
: " in " + base + "\n";
|
|
35
|
+
const errorPath = join(outputDir, `${base}.error.txt`);
|
|
36
|
+
const errorBlock = errors.join("\n").trim() + (errors.length ? "\n" : "");
|
|
37
|
+
const content = errorBlock + locationLine;
|
|
38
|
+
writeFileSync(errorPath, content, "utf-8");
|
|
39
|
+
}
|
|
40
|
+
|
|
15
41
|
/**
|
|
16
42
|
* Generate manifestId: git:<sha> if available, else time:<iso>
|
|
17
43
|
*/
|
|
@@ -69,16 +95,19 @@ export async function compileScenes(
|
|
|
69
95
|
|
|
70
96
|
// Compile each scene
|
|
71
97
|
for (const sceneFile of sceneFiles) {
|
|
98
|
+
let sourceText = "";
|
|
72
99
|
try {
|
|
73
|
-
|
|
100
|
+
sourceText = readFileSync(sceneFile, "utf-8");
|
|
74
101
|
const manifest = compileSceneFromText(sourceText);
|
|
75
102
|
|
|
76
103
|
if (!manifest || !manifest.sceneName) {
|
|
104
|
+
const message = "Failed to compile scene: no sceneName found";
|
|
77
105
|
diagnostics.push({
|
|
78
106
|
severity: "error",
|
|
79
|
-
message
|
|
107
|
+
message,
|
|
80
108
|
source: sceneFile,
|
|
81
109
|
});
|
|
110
|
+
writeSceneErrors(outputDir, sceneFile, [message], sourceText);
|
|
82
111
|
continue;
|
|
83
112
|
}
|
|
84
113
|
|
|
@@ -98,6 +127,14 @@ export async function compileScenes(
|
|
|
98
127
|
writeFileSync(tempPath, json, "utf-8");
|
|
99
128
|
renameSync(tempPath, outputPath);
|
|
100
129
|
|
|
130
|
+
// Remove any prior .error.txt for this scene (same source file base name)
|
|
131
|
+
const errorPath = join(outputDir, `${sceneFileBaseName(sceneFile)}.error.txt`);
|
|
132
|
+
try {
|
|
133
|
+
unlinkSync(errorPath);
|
|
134
|
+
} catch {
|
|
135
|
+
// ignore if missing
|
|
136
|
+
}
|
|
137
|
+
|
|
101
138
|
compiledScenes.push(manifest.sceneName);
|
|
102
139
|
} catch (error) {
|
|
103
140
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -106,6 +143,7 @@ export async function compileScenes(
|
|
|
106
143
|
message: `Scene compile failed: ${message}`,
|
|
107
144
|
source: sceneFile,
|
|
108
145
|
});
|
|
146
|
+
writeSceneErrors(outputDir, sceneFile, [message], sourceText);
|
|
109
147
|
}
|
|
110
148
|
}
|
|
111
149
|
|