@modularcloud/cspec 0.2.0 → 0.3.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/dist/cli.d.ts +6 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +327 -4
- package/dist/editor/assets/index-BV-lxU2y.css +1 -0
- package/dist/editor/assets/index-DL-RbHCV.js +80 -0
- package/dist/editor/index.html +14 -0
- package/package.json +16 -14
- package/README.md +0 -226
- package/dist/config.d.ts +0 -8
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -47
- package/dist/errors.d.ts +0 -10
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js +0 -20
- package/dist/generate.d.ts +0 -11
- package/dist/generate.d.ts.map +0 -1
- package/dist/generate.js +0 -57
- package/dist/glob.d.ts +0 -3
- package/dist/glob.d.ts.map +0 -1
- package/dist/glob.js +0 -49
- package/dist/ids.d.ts +0 -6
- package/dist/ids.d.ts.map +0 -1
- package/dist/ids.js +0 -38
- package/dist/parser.d.ts +0 -55
- package/dist/parser.d.ts.map +0 -1
- package/dist/parser.js +0 -210
- package/dist/render.d.ts +0 -9
- package/dist/render.d.ts.map +0 -1
- package/dist/render.js +0 -91
- package/dist/runtime.d.ts.map +0 -1
- package/dist/workspace.d.ts +0 -13
- package/dist/workspace.d.ts.map +0 -1
- package/dist/workspace.js +0 -31
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<link rel="icon" href="data:," />
|
|
7
|
+
<title>cspec Editor</title>
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-DL-RbHCV.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BV-lxU2y.css">
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<div id="root"></div>
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modularcloud/cspec",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
5
|
-
"type": "module",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "CLI and runtime entrypoint for cspec reusable Markdown blocks.",
|
|
6
5
|
"repository": {
|
|
7
6
|
"type": "git",
|
|
8
7
|
"url": "https://github.com/modularcloud/xspec"
|
|
9
8
|
},
|
|
10
|
-
"
|
|
11
|
-
"url": "https://github.com/modularcloud/xspec/issues"
|
|
12
|
-
},
|
|
13
|
-
"homepage": "https://github.com/modularcloud/xspec#readme",
|
|
9
|
+
"type": "module",
|
|
14
10
|
"bin": {
|
|
15
11
|
"cspec": "dist/bin/cspec.js"
|
|
16
12
|
},
|
|
@@ -19,12 +15,22 @@
|
|
|
19
15
|
".": {
|
|
20
16
|
"types": "./dist/runtime.d.ts",
|
|
21
17
|
"default": "./dist/runtime.js"
|
|
18
|
+
},
|
|
19
|
+
"./cli": {
|
|
20
|
+
"types": "./dist/cli.d.ts",
|
|
21
|
+
"default": "./dist/cli.js"
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
24
|
"scripts": {
|
|
25
|
-
"build": "tsc && node -e \"require('node:fs').chmodSync('dist/bin/cspec.js', 0o755)\"",
|
|
26
|
-
"
|
|
27
|
-
"
|
|
25
|
+
"build": "tsc -p tsconfig.json && cp ../cspec-core/dist/runtime.js dist/runtime.js && cp ../cspec-core/dist/runtime.d.ts dist/runtime.d.ts && rm -rf dist/editor && mkdir -p dist/editor && cp -R ../cspec-app/dist/. dist/editor/ && node -e \"require('node:fs').chmodSync('dist/bin/cspec.js', 0o755)\"",
|
|
26
|
+
"check": "tsc -p tsconfig.json --noEmit",
|
|
27
|
+
"test": "node --test test.js"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@modularcloud/cspec-core": "^0.3.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@modularcloud/cspec-app": "0.1.0"
|
|
28
34
|
},
|
|
29
35
|
"files": [
|
|
30
36
|
"dist",
|
|
@@ -44,9 +50,5 @@
|
|
|
44
50
|
},
|
|
45
51
|
"engines": {
|
|
46
52
|
"node": ">=20"
|
|
47
|
-
},
|
|
48
|
-
"devDependencies": {
|
|
49
|
-
"@types/node": "^25.9.1",
|
|
50
|
-
"typescript": "^6.0.3"
|
|
51
53
|
}
|
|
52
54
|
}
|
package/README.md
DELETED
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
# cspec
|
|
2
|
-
|
|
3
|
-
Minimal MDX content block compiler implementing the cspec reusable-block subset.
|
|
4
|
-
|
|
5
|
-
`cspec` lets you define named content blocks in MDX files, reference those blocks from other MDX files, and compile everything to plain Markdown. It is useful for prompts, process docs, and instructions where a block of text should have one source of truth.
|
|
6
|
-
|
|
7
|
-
This package is published as `@modularcloud/cspec` and installs a `cspec` CLI.
|
|
8
|
-
|
|
9
|
-
## Install
|
|
10
|
-
|
|
11
|
-
```sh
|
|
12
|
-
npm install --save-dev @modularcloud/cspec
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Run with:
|
|
16
|
-
|
|
17
|
-
```sh
|
|
18
|
-
npx cspec build
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Quick Start
|
|
22
|
-
|
|
23
|
-
Create a source document:
|
|
24
|
-
|
|
25
|
-
```mdx
|
|
26
|
-
import { S } from "cspec"
|
|
27
|
-
|
|
28
|
-
<S id="writing">
|
|
29
|
-
Writing requirements.
|
|
30
|
-
|
|
31
|
-
<S id="writing.beSpecific">
|
|
32
|
-
Be specific and avoid vague language.
|
|
33
|
-
</S>
|
|
34
|
-
|
|
35
|
-
<S id="writing.askOnAmbiguity">
|
|
36
|
-
Ask for clarification when the requested behavior is ambiguous.
|
|
37
|
-
</S>
|
|
38
|
-
</S>
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Reference it from another document:
|
|
42
|
-
|
|
43
|
-
```mdx
|
|
44
|
-
import PROCESS from "./PROCESS.cspec"
|
|
45
|
-
|
|
46
|
-
# Agent Instructions
|
|
47
|
-
|
|
48
|
-
Follow this rule:
|
|
49
|
-
|
|
50
|
-
{PROCESS.writing.beSpecific.$}
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Build:
|
|
54
|
-
|
|
55
|
-
```sh
|
|
56
|
-
npx cspec build
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
The compiler writes:
|
|
60
|
-
|
|
61
|
-
```txt
|
|
62
|
-
PROCESS.cspec.ts
|
|
63
|
-
PROCESS.md
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
and the consuming Markdown becomes:
|
|
67
|
-
|
|
68
|
-
```md
|
|
69
|
-
# Agent Instructions
|
|
70
|
-
|
|
71
|
-
Follow this rule:
|
|
72
|
-
|
|
73
|
-
Be specific and avoid vague language.
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
## Commands
|
|
77
|
-
|
|
78
|
-
```sh
|
|
79
|
-
npx cspec build
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
Compiles configured `.mdx` files, writes generated `.cspec.ts` modules, and writes `.md` files when Markdown emission is enabled.
|
|
83
|
-
|
|
84
|
-
```sh
|
|
85
|
-
npx cspec check
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
Validates the workspace and fails if generated files are stale.
|
|
89
|
-
|
|
90
|
-
```sh
|
|
91
|
-
npx cspec ids
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
Lists block IDs by source file.
|
|
95
|
-
|
|
96
|
-
```sh
|
|
97
|
-
npx cspec ids --tree
|
|
98
|
-
npx cspec ids --json
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
Prints IDs as a tree or JSON.
|
|
102
|
-
|
|
103
|
-
## Configuration
|
|
104
|
-
|
|
105
|
-
Add `cspec.config.ts`:
|
|
106
|
-
|
|
107
|
-
```ts
|
|
108
|
-
import { defineConfig } from "cspec"
|
|
109
|
-
|
|
110
|
-
export default defineConfig({
|
|
111
|
-
specs: {
|
|
112
|
-
docs: ["docs/**/*.mdx"],
|
|
113
|
-
prompts: ["prompts/**/*.mdx"]
|
|
114
|
-
},
|
|
115
|
-
markdown: {
|
|
116
|
-
emit: true
|
|
117
|
-
}
|
|
118
|
-
})
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
Without a config file, cspec defaults to:
|
|
122
|
-
|
|
123
|
-
```ts
|
|
124
|
-
{
|
|
125
|
-
specs: {
|
|
126
|
-
default: ["**/*.mdx"]
|
|
127
|
-
},
|
|
128
|
-
markdown: {
|
|
129
|
-
emit: true
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
## Authoring Blocks
|
|
135
|
-
|
|
136
|
-
Use `<S>` or `<Spec>` to define a block:
|
|
137
|
-
|
|
138
|
-
```mdx
|
|
139
|
-
<S id="tone">
|
|
140
|
-
Use clear, direct language.
|
|
141
|
-
</S>
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
Nested block IDs must be structural:
|
|
145
|
-
|
|
146
|
-
```mdx
|
|
147
|
-
<S id="writing">
|
|
148
|
-
Writing rules.
|
|
149
|
-
|
|
150
|
-
<S id="writing.beSpecific">
|
|
151
|
-
Be specific.
|
|
152
|
-
</S>
|
|
153
|
-
</S>
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
The parent block value includes its full subtree, so `writing.$` includes both `Writing rules.` and `Be specific.`
|
|
157
|
-
|
|
158
|
-
## Embedding Blocks
|
|
159
|
-
|
|
160
|
-
Embed an external block with `.$`:
|
|
161
|
-
|
|
162
|
-
```mdx
|
|
163
|
-
import RULES from "./RULES.cspec"
|
|
164
|
-
|
|
165
|
-
{RULES.writing.beSpecific.$}
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
Embed a local block with `ref("id").$`:
|
|
169
|
-
|
|
170
|
-
```mdx
|
|
171
|
-
import { ref } from "cspec"
|
|
172
|
-
|
|
173
|
-
{ref("writing.beSpecific").$}
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
For non-identifier-safe segments, use bracket access:
|
|
177
|
-
|
|
178
|
-
```mdx
|
|
179
|
-
{RULES.writing["be-specific"].$}
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
## Generated Modules
|
|
183
|
-
|
|
184
|
-
For each source file:
|
|
185
|
-
|
|
186
|
-
```txt
|
|
187
|
-
RULES.mdx
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
cspec emits:
|
|
191
|
-
|
|
192
|
-
```txt
|
|
193
|
-
RULES.cspec.ts
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
The generated module has a nested object shape:
|
|
197
|
-
|
|
198
|
-
```ts
|
|
199
|
-
RULES.$
|
|
200
|
-
RULES.writing.$
|
|
201
|
-
RULES.writing.beSpecific.$
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
These values are string literals where practical, so TypeScript can catch missing paths in consuming code.
|
|
205
|
-
|
|
206
|
-
## Validation
|
|
207
|
-
|
|
208
|
-
cspec validates:
|
|
209
|
-
|
|
210
|
-
- missing block IDs
|
|
211
|
-
- invalid structural nesting
|
|
212
|
-
- invalid ID segments
|
|
213
|
-
- duplicate IDs
|
|
214
|
-
- unresolved imports
|
|
215
|
-
- unknown local or external references
|
|
216
|
-
- dynamic `ref(...)` calls
|
|
217
|
-
- embedding cycles
|
|
218
|
-
- stale generated output during `cspec check`
|
|
219
|
-
|
|
220
|
-
## Development
|
|
221
|
-
|
|
222
|
-
```sh
|
|
223
|
-
npm test
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
The implementation is written in TypeScript and compiled to `dist` for publishing. The package has no runtime dependencies.
|
package/dist/config.d.ts
DELETED
package/dist/config.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAChC,QAAQ,EAAE;QACR,IAAI,EAAE,OAAO,CAAC;KACf,CAAC;CACH;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAYlE"}
|
package/dist/config.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { pathToFileURL } from "node:url";
|
|
4
|
-
import { CspecError } from "./errors.js";
|
|
5
|
-
export async function loadConfig(cwd) {
|
|
6
|
-
const candidates = ["cspec.config.js", "cspec.config.mjs", "cspec.config.cjs", "cspec.config.ts"];
|
|
7
|
-
for (const name of candidates) {
|
|
8
|
-
const file = path.join(cwd, name);
|
|
9
|
-
if (!fs.existsSync(file))
|
|
10
|
-
continue;
|
|
11
|
-
const config = name.endsWith(".ts") ? loadTsConfig(file) : await importConfig(file);
|
|
12
|
-
return normalizeConfig(config);
|
|
13
|
-
}
|
|
14
|
-
return normalizeConfig({
|
|
15
|
-
specs: { default: ["**/*.mdx"] },
|
|
16
|
-
markdown: { emit: true }
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
async function importConfig(file) {
|
|
20
|
-
const module = await import(`${pathToFileURL(file).href}?t=${Date.now()}`);
|
|
21
|
-
return module.default ?? module;
|
|
22
|
-
}
|
|
23
|
-
function loadTsConfig(file) {
|
|
24
|
-
const source = fs.readFileSync(file, "utf8")
|
|
25
|
-
.replace(/^\s*import\s+.*?(?:;\s*)?$/gm, "")
|
|
26
|
-
.replace(/export\s+default\s+defineConfig\s*\(/, "return (")
|
|
27
|
-
.replace(/export\s+default\s+/, "return ");
|
|
28
|
-
try {
|
|
29
|
-
return Function("defineConfig", source)((value) => value);
|
|
30
|
-
}
|
|
31
|
-
catch (error) {
|
|
32
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
33
|
-
throw new CspecError(`Unable to load ${path.basename(file)}: ${message}`, { file });
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
function normalizeConfig(config) {
|
|
37
|
-
const candidate = isConfigShape(config) ? config : {};
|
|
38
|
-
return {
|
|
39
|
-
specs: candidate.specs && Object.keys(candidate.specs).length ? candidate.specs : { default: ["**/*.mdx"] },
|
|
40
|
-
markdown: {
|
|
41
|
-
emit: candidate.markdown?.emit !== false
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
function isConfigShape(value) {
|
|
46
|
-
return typeof value === "object" && value !== null;
|
|
47
|
-
}
|
package/dist/errors.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export interface ErrorDetails {
|
|
2
|
-
file?: string;
|
|
3
|
-
line?: number;
|
|
4
|
-
}
|
|
5
|
-
export declare class CspecError extends Error {
|
|
6
|
-
details: ErrorDetails;
|
|
7
|
-
constructor(message: string, details?: ErrorDetails);
|
|
8
|
-
}
|
|
9
|
-
export declare function formatError(error: unknown): string;
|
|
10
|
-
//# sourceMappingURL=errors.d.ts.map
|
package/dist/errors.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,UAAW,SAAQ,KAAK;IACnC,OAAO,EAAE,YAAY,CAAC;gBAEV,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB;CAKxD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAQlD"}
|
package/dist/errors.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export class CspecError extends Error {
|
|
2
|
-
details;
|
|
3
|
-
constructor(message, details = {}) {
|
|
4
|
-
super(message);
|
|
5
|
-
this.name = "CspecError";
|
|
6
|
-
this.details = details;
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
export function formatError(error) {
|
|
10
|
-
if (!(error instanceof Error))
|
|
11
|
-
return String(error);
|
|
12
|
-
if (!(error instanceof CspecError) || !error.details.file)
|
|
13
|
-
return error.message;
|
|
14
|
-
if (!error?.details?.file)
|
|
15
|
-
return error.message;
|
|
16
|
-
const location = error.details.line
|
|
17
|
-
? `${error.details.file}:${error.details.line}`
|
|
18
|
-
: error.details.file;
|
|
19
|
-
return `${location}: ${error.message}`;
|
|
20
|
-
}
|
package/dist/generate.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { CspecDocument } from "./parser.js";
|
|
2
|
-
export interface GeneratedFile {
|
|
3
|
-
file: string;
|
|
4
|
-
content: string;
|
|
5
|
-
}
|
|
6
|
-
export interface GenerateOptions {
|
|
7
|
-
markdownEmit: boolean;
|
|
8
|
-
}
|
|
9
|
-
export declare function generatedFilesFor(doc: CspecDocument, options: GenerateOptions): GeneratedFile[];
|
|
10
|
-
export declare function generateTypeScript(doc: CspecDocument): string;
|
|
11
|
-
//# sourceMappingURL=generate.d.ts.map
|
package/dist/generate.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,OAAO,CAAC;CACvB;AAOD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,eAAe,GAAG,aAAa,EAAE,CAe/F;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAgB7D"}
|
package/dist/generate.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
export function generatedFilesFor(doc, options) {
|
|
3
|
-
const base = doc.file.replace(/\.mdx$/i, "");
|
|
4
|
-
const files = [
|
|
5
|
-
{
|
|
6
|
-
file: `${base}.cspec.ts`,
|
|
7
|
-
content: generateTypeScript(doc)
|
|
8
|
-
}
|
|
9
|
-
];
|
|
10
|
-
if (options.markdownEmit) {
|
|
11
|
-
files.push({
|
|
12
|
-
file: `${base}.md`,
|
|
13
|
-
content: `${doc.root.compiled}\n`
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
return files;
|
|
17
|
-
}
|
|
18
|
-
export function generateTypeScript(doc) {
|
|
19
|
-
const name = safeConstName(path.basename(doc.file, ".mdx"));
|
|
20
|
-
const tree = { $: doc.root.compiled ?? "" };
|
|
21
|
-
for (const block of doc.blocks.values()) {
|
|
22
|
-
let cursor = tree;
|
|
23
|
-
for (const segment of block.segments) {
|
|
24
|
-
let next = cursor[segment];
|
|
25
|
-
if (!isGeneratedTree(next)) {
|
|
26
|
-
next = {};
|
|
27
|
-
cursor[segment] = next;
|
|
28
|
-
}
|
|
29
|
-
cursor = next;
|
|
30
|
-
}
|
|
31
|
-
cursor.$ = block.compiled ?? "";
|
|
32
|
-
}
|
|
33
|
-
return `const ${name} = ${printObject(tree, 0)} as const;\n\nexport default ${name};\n`;
|
|
34
|
-
}
|
|
35
|
-
function safeConstName(name) {
|
|
36
|
-
const cleaned = name.replace(/\W+/g, "_").replace(/^(\d)/, "_$1");
|
|
37
|
-
return cleaned || "SPEC";
|
|
38
|
-
}
|
|
39
|
-
function printObject(value, depth) {
|
|
40
|
-
if (typeof value === "string")
|
|
41
|
-
return JSON.stringify(value);
|
|
42
|
-
const indent = " ".repeat(depth);
|
|
43
|
-
const childIndent = " ".repeat(depth + 1);
|
|
44
|
-
const entries = Object.entries(value);
|
|
45
|
-
if (entries.length === 0)
|
|
46
|
-
return "{}";
|
|
47
|
-
const body = entries
|
|
48
|
-
.map(([key, child]) => `${childIndent}${printKey(key)}: ${printObject(child ?? "", depth + 1)}`)
|
|
49
|
-
.join(",\n");
|
|
50
|
-
return `{\n${body}\n${indent}}`;
|
|
51
|
-
}
|
|
52
|
-
function printKey(key) {
|
|
53
|
-
return /^[A-Za-z_$][\w$]*$/.test(key) ? key : JSON.stringify(key);
|
|
54
|
-
}
|
|
55
|
-
function isGeneratedTree(value) {
|
|
56
|
-
return typeof value === "object" && value !== null;
|
|
57
|
-
}
|
package/dist/glob.d.ts
DELETED
package/dist/glob.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../src/glob.ts"],"names":[],"mappings":"AAGA,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,CAYpF;AAkBD,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAS/D"}
|
package/dist/glob.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
export function discoverFiles(cwd, specs) {
|
|
4
|
-
const patterns = [];
|
|
5
|
-
for (const group of Object.values(specs))
|
|
6
|
-
patterns.push(...group);
|
|
7
|
-
const files = new Set();
|
|
8
|
-
for (const pattern of patterns) {
|
|
9
|
-
for (const file of walk(cwd)) {
|
|
10
|
-
const rel = path.relative(cwd, file).split(path.sep).join("/");
|
|
11
|
-
if (isGenerated(rel))
|
|
12
|
-
continue;
|
|
13
|
-
if (matchGlob(pattern, rel))
|
|
14
|
-
files.add(file);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
return [...files].sort();
|
|
18
|
-
}
|
|
19
|
-
function walk(dir) {
|
|
20
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
21
|
-
const files = [];
|
|
22
|
-
for (const entry of entries) {
|
|
23
|
-
if (entry.name === "node_modules" || entry.name === ".git")
|
|
24
|
-
continue;
|
|
25
|
-
const full = path.join(dir, entry.name);
|
|
26
|
-
if (entry.isDirectory())
|
|
27
|
-
files.push(...walk(full));
|
|
28
|
-
else if (entry.isFile())
|
|
29
|
-
files.push(full);
|
|
30
|
-
}
|
|
31
|
-
return files;
|
|
32
|
-
}
|
|
33
|
-
function isGenerated(rel) {
|
|
34
|
-
return rel.endsWith(".cspec.ts") || rel.endsWith(".md");
|
|
35
|
-
}
|
|
36
|
-
export function matchGlob(pattern, rel) {
|
|
37
|
-
if (pattern.startsWith("**/") && matchGlob(pattern.slice(3), rel))
|
|
38
|
-
return true;
|
|
39
|
-
if (pattern.includes("/**/") && matchGlob(pattern.replace("/**/", "/"), rel))
|
|
40
|
-
return true;
|
|
41
|
-
const escaped = pattern.split(/(\*\*|\*)/g).map((part) => {
|
|
42
|
-
if (part === "**")
|
|
43
|
-
return ".*";
|
|
44
|
-
if (part === "*")
|
|
45
|
-
return "[^/]*";
|
|
46
|
-
return part.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
47
|
-
}).join("");
|
|
48
|
-
return new RegExp(`^${escaped}$`).test(rel);
|
|
49
|
-
}
|
package/dist/ids.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { ErrorDetails } from "./errors.js";
|
|
2
|
-
export declare function splitId(id: string, details?: ErrorDetails): string[];
|
|
3
|
-
export declare function validateSegment(segment: string, details?: ErrorDetails): void;
|
|
4
|
-
export declare function assertStructuralId(id: string, parentId: string, details?: ErrorDetails): void;
|
|
5
|
-
export declare function idToSegments(id: string): string[];
|
|
6
|
-
//# sourceMappingURL=ids.d.ts.map
|
package/dist/ids.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../src/ids.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIhD,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,MAAM,EAAE,CAUxE;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,IAAI,CAcjF;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,IAAI,CAQjG;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAEjD"}
|
package/dist/ids.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { CspecError } from "./errors.js";
|
|
2
|
-
const RESERVED = new Set(["$", "__proto__", "prototype", "constructor"]);
|
|
3
|
-
export function splitId(id, details = {}) {
|
|
4
|
-
if (typeof id !== "string") {
|
|
5
|
-
throw new CspecError("Block id must be a string.", details);
|
|
6
|
-
}
|
|
7
|
-
if (id.trim() !== id) {
|
|
8
|
-
throw new CspecError(`Invalid block id "${id}"; ids must not have leading or trailing whitespace.`, details);
|
|
9
|
-
}
|
|
10
|
-
const segments = id.split(".");
|
|
11
|
-
for (const segment of segments)
|
|
12
|
-
validateSegment(segment, details);
|
|
13
|
-
return segments;
|
|
14
|
-
}
|
|
15
|
-
export function validateSegment(segment, details = {}) {
|
|
16
|
-
if (!segment) {
|
|
17
|
-
throw new CspecError("Invalid empty id segment.", details);
|
|
18
|
-
}
|
|
19
|
-
if (segment.trim() !== segment) {
|
|
20
|
-
throw new CspecError(`Invalid id segment "${segment}"; segments must not have leading or trailing whitespace.`, details);
|
|
21
|
-
}
|
|
22
|
-
if (/[\u0000-\u001f\u007f]/u.test(segment)) {
|
|
23
|
-
throw new CspecError(`Invalid id segment "${segment}"; control characters are not allowed.`, details);
|
|
24
|
-
}
|
|
25
|
-
if (RESERVED.has(segment)) {
|
|
26
|
-
const reason = segment === "$" ? '"$" is reserved for block values.' : `"${segment}" is reserved.`;
|
|
27
|
-
throw new CspecError(`Invalid id segment "${segment}"; ${reason}`, details);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
export function assertStructuralId(id, parentId, details = {}) {
|
|
31
|
-
splitId(id, details);
|
|
32
|
-
if (parentId && !id.startsWith(`${parentId}.`)) {
|
|
33
|
-
throw new CspecError(`Child block id must begin with parent id plus ".".\nExpected id matching "${parentId}.<segment>".\nReceived "${id}".`, details);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
export function idToSegments(id) {
|
|
37
|
-
return id ? id.split(".") : [];
|
|
38
|
-
}
|
package/dist/parser.d.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
export interface CspecImport {
|
|
2
|
-
kind: "cspec" | "module";
|
|
3
|
-
clause: string;
|
|
4
|
-
specifier: string;
|
|
5
|
-
start: number;
|
|
6
|
-
end: number;
|
|
7
|
-
local?: string;
|
|
8
|
-
}
|
|
9
|
-
export interface LocalReference {
|
|
10
|
-
kind: "local";
|
|
11
|
-
raw: string;
|
|
12
|
-
start: number;
|
|
13
|
-
end: number;
|
|
14
|
-
id: string | null;
|
|
15
|
-
validStatic: boolean;
|
|
16
|
-
expression: string;
|
|
17
|
-
}
|
|
18
|
-
export interface ExternalReference {
|
|
19
|
-
kind: "external";
|
|
20
|
-
raw: string;
|
|
21
|
-
start: number;
|
|
22
|
-
end: number;
|
|
23
|
-
local: string;
|
|
24
|
-
path: string;
|
|
25
|
-
expression: string;
|
|
26
|
-
}
|
|
27
|
-
export type CspecReference = LocalReference | ExternalReference;
|
|
28
|
-
export interface CspecBlock {
|
|
29
|
-
id: string;
|
|
30
|
-
parentId: string | null;
|
|
31
|
-
openStart: number;
|
|
32
|
-
openEnd: number;
|
|
33
|
-
contentStart: number;
|
|
34
|
-
contentEnd: number;
|
|
35
|
-
closeStart: number | null;
|
|
36
|
-
closeEnd: number | null;
|
|
37
|
-
tag: string;
|
|
38
|
-
children: CspecBlock[];
|
|
39
|
-
segments: string[];
|
|
40
|
-
line: number;
|
|
41
|
-
compiled: string | null;
|
|
42
|
-
}
|
|
43
|
-
export interface CspecDocument {
|
|
44
|
-
file: string;
|
|
45
|
-
source: string;
|
|
46
|
-
root: CspecBlock;
|
|
47
|
-
blocks: Map<string, CspecBlock>;
|
|
48
|
-
imports: CspecImport[];
|
|
49
|
-
rangesToRemove: Array<[number, number]>;
|
|
50
|
-
references: CspecReference[];
|
|
51
|
-
}
|
|
52
|
-
export declare function parseSource(file: string, source: string): CspecDocument;
|
|
53
|
-
export declare function resolveImportPath(fromFile: string, specifier: string): string;
|
|
54
|
-
export declare function lineAt(source: string, index: number): number;
|
|
55
|
-
//# sourceMappingURL=parser.d.ts.map
|
package/dist/parser.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,UAAU,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,cAAc,GAAG,cAAc,GAAG,iBAAiB,CAAC;AAEhE,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAChC,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,cAAc,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACxC,UAAU,EAAE,cAAc,EAAE,CAAC;CAC9B;AAOD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,CAqEvE;AA6ID,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAG7E;AAED,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAM5D"}
|