@intentius/chant 0.18.17 → 0.18.18
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/commands/init-lexicon/templates/lint.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon/templates/project.d.ts +8 -0
- package/dist/cli/commands/init-lexicon/templates/project.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon/templates/spec.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
- package/dist/yaml.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +4 -4
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/generate.ts +2 -2
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/lint/rules/index.ts +6 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/spec/fetch.ts +8 -7
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/validate-cli.ts +2 -1
- package/src/cli/commands/__fixtures__/init-lexicon-output/tsconfig.build.json +27 -0
- package/src/cli/commands/__snapshots__/init-lexicon.test.ts.snap +2 -2
- package/src/cli/commands/init-lexicon/templates/codegen.ts +2 -2
- package/src/cli/commands/init-lexicon/templates/lint.ts +7 -1
- package/src/cli/commands/init-lexicon/templates/project.ts +36 -5
- package/src/cli/commands/init-lexicon/templates/spec.ts +8 -7
- package/src/cli/commands/init-lexicon.test.ts +33 -0
- package/src/cli/commands/init-lexicon.ts +2 -1
- package/src/yaml.test.ts +33 -0
- package/src/yaml.ts +106 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/init-lexicon/templates/lint.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAoB1E;AAED,wBAAgB,wBAAwB,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/init-lexicon/templates/lint.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAoB1E;AAED,wBAAgB,wBAAwB,IAAI,MAAM,CASjD"}
|
|
@@ -5,6 +5,14 @@ export declare function generatePackageJson(name: string, names: {
|
|
|
5
5
|
packageName: string;
|
|
6
6
|
}): string;
|
|
7
7
|
export declare function generateTsConfig(): string;
|
|
8
|
+
/**
|
|
9
|
+
* Build config used by `npm run build` (and CI's `tsc --noEmit`). Uses `bundler`
|
|
10
|
+
* resolution + the `development` condition so `@intentius/chant/*` resolves to the
|
|
11
|
+
* workspace source, and excludes tests/docs — the same setup the shipped lexicons
|
|
12
|
+
* use. (The plain `tsconfig.json` extends the monorepo root and can't be tsc'd on
|
|
13
|
+
* its own.)
|
|
14
|
+
*/
|
|
15
|
+
export declare function generateTsConfigBuild(): string;
|
|
8
16
|
export declare function generateJustfile(name: string): string;
|
|
9
17
|
export declare function generateGitignore(): string;
|
|
10
18
|
export declare function generateReadme(name: string, names: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/init-lexicon/templates/project.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/init-lexicon/templates/project.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CA+BxF;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAWzC;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAmB9C;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA4BrD;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAK1C;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CA4BnF;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE;IAAE,iBAAiB,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CA0BnH;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA8BvD;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAO9C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/init-lexicon/templates/spec.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wBAAgB,mBAAmB,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/init-lexicon/templates/spec.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wBAAgB,mBAAmB,IAAI,MAAM,CAwB5C;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CA2B5C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init-lexicon.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init-lexicon.ts"],"names":[],"mappings":"AAeA;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,0BAA0B;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAQD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM;;;;;EAQvC;AAqBD;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,
|
|
1
|
+
{"version":3,"file":"init-lexicon.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init-lexicon.ts"],"names":[],"mappings":"AAeA;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,0BAA0B;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAQD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM;;;;;EAQvC;AAqBD;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAqHhG;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBrF"}
|
package/dist/yaml.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yaml.d.ts","sourceRoot":"","sources":["../src/yaml.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CA2G/D;AAMD,sCAAsC;AACtC,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASlE;
|
|
1
|
+
{"version":3,"file":"yaml.d.ts","sourceRoot":"","sources":["../src/yaml.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CA2G/D;AAMD,sCAAsC;AACtC,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASlE;AAiFD;;GAEG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EAAE,EACf,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,WAAW,CA8Eb;AA+DD;;GAEG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EAAE,EACf,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,WAAW,CAyEb;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAelD"}
|
package/package.json
CHANGED
|
@@ -18,12 +18,12 @@
|
|
|
18
18
|
"generate": "npx tsx src/codegen/generate-cli.ts",
|
|
19
19
|
"validate": "npx tsx src/validate-cli.ts",
|
|
20
20
|
"docs": "npx tsx src/codegen/docs-cli.ts",
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
"dependencies": {
|
|
24
|
-
"@intentius/chant": "workspace:*"
|
|
21
|
+
"build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
|
22
|
+
"prepack": "npm run generate && npm run validate && npm run build"
|
|
25
23
|
},
|
|
26
24
|
"devDependencies": {
|
|
25
|
+
"@intentius/chant": "*",
|
|
26
|
+
"tsc-alias": "^1.8.17",
|
|
27
27
|
"typescript": "^5.9.3"
|
|
28
28
|
}
|
|
29
29
|
}
|
|
@@ -8,7 +8,7 @@ import { fileURLToPath } from "url";
|
|
|
8
8
|
*
|
|
9
9
|
* Each callback has a TODO describing what to implement.
|
|
10
10
|
*/
|
|
11
|
-
export async function generate(options?: { verbose?: boolean }): Promise<GenerateResult> {
|
|
11
|
+
export async function generate(options?: { verbose?: boolean; force?: boolean }): Promise<GenerateResult> {
|
|
12
12
|
const result = await generatePipeline({
|
|
13
13
|
// Must return Map<typeName, Buffer> — each entry is one schema file.
|
|
14
14
|
// Example: fetch a zip, extract JSON files, key by type name.
|
|
@@ -49,7 +49,7 @@ export async function generate(options?: { verbose?: boolean }): Promise<Generat
|
|
|
49
49
|
generateRuntimeIndex: (results, naming) => {
|
|
50
50
|
throw new Error("TODO: implement generateRuntimeIndex — produce index.ts content");
|
|
51
51
|
},
|
|
52
|
-
});
|
|
52
|
+
}, options);
|
|
53
53
|
|
|
54
54
|
if (options?.verbose) {
|
|
55
55
|
console.error(`Generated ${result.resources} resources, ${result.properties} property types`);
|
|
@@ -1 +1,7 @@
|
|
|
1
|
+
import type { LintRule } from "@intentius/chant/lint/rule";
|
|
2
|
+
import { sampleRule } from "./sample";
|
|
3
|
+
|
|
1
4
|
export { sampleRule } from "./sample";
|
|
5
|
+
|
|
6
|
+
/** All lint rules provided by this lexicon (imported by plugin.ts's lintRules()). */
|
|
7
|
+
export const rules: LintRule[] = [sampleRule];
|
|
@@ -9,13 +9,14 @@ const CACHE_FILE = ".cache/schemas.zip";
|
|
|
9
9
|
*
|
|
10
10
|
* TODO: Point SCHEMA_URL at your real upstream schema source.
|
|
11
11
|
*/
|
|
12
|
-
export async function fetchSchemas(options?: { force?: boolean }): Promise<Map<string,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
cacheFile: CACHE_FILE,
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
export async function fetchSchemas(options?: { force?: boolean }): Promise<Map<string, Buffer>> {
|
|
13
|
+
// `force` is the second argument to fetchWithCache (not a FetchConfig field).
|
|
14
|
+
const zipData = await fetchWithCache(
|
|
15
|
+
{ url: SCHEMA_URL, cacheFile: CACHE_FILE },
|
|
16
|
+
options?.force,
|
|
17
|
+
);
|
|
18
18
|
|
|
19
|
-
// TODO: Adjust the filter to match your schema file names
|
|
19
|
+
// TODO: Adjust the filter to match your schema file names. extractFromZip yields
|
|
20
|
+
// Buffers — decode with `.toString()` in parse.ts as needed.
|
|
20
21
|
return extractFromZip(zipData, (name) => name.endsWith(".json"));
|
|
21
22
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"noEmit": false,
|
|
5
|
+
"declaration": true,
|
|
6
|
+
"declarationMap": true,
|
|
7
|
+
"outDir": "dist",
|
|
8
|
+
"rootDir": "src",
|
|
9
|
+
"paths": {},
|
|
10
|
+
"moduleResolution": "bundler",
|
|
11
|
+
"customConditions": [
|
|
12
|
+
"development"
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
"include": [
|
|
16
|
+
"src/**/*"
|
|
17
|
+
],
|
|
18
|
+
"exclude": [
|
|
19
|
+
"**/*.test.ts",
|
|
20
|
+
"node_modules",
|
|
21
|
+
"dist",
|
|
22
|
+
"docs"
|
|
23
|
+
],
|
|
24
|
+
"tsc-alias": {
|
|
25
|
+
"resolveFullPaths": true
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -11,7 +11,7 @@ import { fileURLToPath } from "url";
|
|
|
11
11
|
*
|
|
12
12
|
* Each callback has a TODO describing what to implement.
|
|
13
13
|
*/
|
|
14
|
-
export async function generate(options?: { verbose?: boolean }): Promise<GenerateResult> {
|
|
14
|
+
export async function generate(options?: { verbose?: boolean; force?: boolean }): Promise<GenerateResult> {
|
|
15
15
|
const result = await generatePipeline({
|
|
16
16
|
// Must return Map<typeName, Buffer> — each entry is one schema file.
|
|
17
17
|
// Example: fetch a zip, extract JSON files, key by type name.
|
|
@@ -52,7 +52,7 @@ export async function generate(options?: { verbose?: boolean }): Promise<Generat
|
|
|
52
52
|
generateRuntimeIndex: (results, naming) => {
|
|
53
53
|
throw new Error("TODO: implement generateRuntimeIndex — produce index.ts content");
|
|
54
54
|
},
|
|
55
|
-
});
|
|
55
|
+
}, options);
|
|
56
56
|
|
|
57
57
|
if (options?.verbose) {
|
|
58
58
|
console.error(\`Generated \${result.resources} resources, \${result.properties} property types\`);
|
|
@@ -13,7 +13,7 @@ import { fileURLToPath } from "url";
|
|
|
13
13
|
*
|
|
14
14
|
* Each callback has a TODO describing what to implement.
|
|
15
15
|
*/
|
|
16
|
-
export async function generate(options?: { verbose?: boolean }): Promise<GenerateResult> {
|
|
16
|
+
export async function generate(options?: { verbose?: boolean; force?: boolean }): Promise<GenerateResult> {
|
|
17
17
|
const result = await generatePipeline({
|
|
18
18
|
// Must return Map<typeName, Buffer> — each entry is one schema file.
|
|
19
19
|
// Example: fetch a zip, extract JSON files, key by type name.
|
|
@@ -54,7 +54,7 @@ export async function generate(options?: { verbose?: boolean }): Promise<Generat
|
|
|
54
54
|
generateRuntimeIndex: (results, naming) => {
|
|
55
55
|
throw new Error("TODO: implement generateRuntimeIndex — produce index.ts content");
|
|
56
56
|
},
|
|
57
|
-
});
|
|
57
|
+
}, options);
|
|
58
58
|
|
|
59
59
|
if (options?.verbose) {
|
|
60
60
|
console.error(\`Generated \${result.resources} resources, \${result.properties} property types\`);
|
|
@@ -25,6 +25,12 @@ export const sampleRule: LintRule = {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export function generateLintRulesIndexTs(): string {
|
|
28
|
-
return `
|
|
28
|
+
return `import type { LintRule } from "@intentius/chant/lint/rule";
|
|
29
|
+
import { sampleRule } from "./sample";
|
|
30
|
+
|
|
31
|
+
export { sampleRule } from "./sample";
|
|
32
|
+
|
|
33
|
+
/** All lint rules provided by this lexicon (imported by plugin.ts's lintRules()). */
|
|
34
|
+
export const rules: LintRule[] = [sampleRule];
|
|
29
35
|
`;
|
|
30
36
|
}
|
|
@@ -20,12 +20,14 @@ export function generatePackageJson(name: string, names: { packageName: string }
|
|
|
20
20
|
generate: "npx tsx src/codegen/generate-cli.ts",
|
|
21
21
|
validate: "npx tsx src/validate-cli.ts",
|
|
22
22
|
docs: "npx tsx src/codegen/docs-cli.ts",
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
dependencies: {
|
|
26
|
-
"@intentius/chant": "workspace:*",
|
|
23
|
+
build: "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
|
24
|
+
prepack: "npm run generate && npm run validate && npm run build",
|
|
27
25
|
},
|
|
28
26
|
devDependencies: {
|
|
27
|
+
// `*` (not `workspace:*`) so a fresh lexicon `npm install`s under plain npm
|
|
28
|
+
// (the `workspace:` protocol is rejected outside a workspace).
|
|
29
|
+
"@intentius/chant": "*",
|
|
30
|
+
"tsc-alias": "^1.8.17",
|
|
29
31
|
typescript: "^5.9.3",
|
|
30
32
|
},
|
|
31
33
|
};
|
|
@@ -46,6 +48,34 @@ export function generateTsConfig(): string {
|
|
|
46
48
|
return JSON.stringify(config, null, 2) + "\n";
|
|
47
49
|
}
|
|
48
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Build config used by `npm run build` (and CI's `tsc --noEmit`). Uses `bundler`
|
|
53
|
+
* resolution + the `development` condition so `@intentius/chant/*` resolves to the
|
|
54
|
+
* workspace source, and excludes tests/docs — the same setup the shipped lexicons
|
|
55
|
+
* use. (The plain `tsconfig.json` extends the monorepo root and can't be tsc'd on
|
|
56
|
+
* its own.)
|
|
57
|
+
*/
|
|
58
|
+
export function generateTsConfigBuild(): string {
|
|
59
|
+
const config = {
|
|
60
|
+
extends: "../../tsconfig.json",
|
|
61
|
+
compilerOptions: {
|
|
62
|
+
noEmit: false,
|
|
63
|
+
declaration: true,
|
|
64
|
+
declarationMap: true,
|
|
65
|
+
outDir: "dist",
|
|
66
|
+
rootDir: "src",
|
|
67
|
+
paths: {},
|
|
68
|
+
moduleResolution: "bundler",
|
|
69
|
+
customConditions: ["development"],
|
|
70
|
+
},
|
|
71
|
+
include: ["src/**/*"],
|
|
72
|
+
exclude: ["**/*.test.ts", "node_modules", "dist", "docs"],
|
|
73
|
+
"tsc-alias": { resolveFullPaths: true },
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
return JSON.stringify(config, null, 2) + "\n";
|
|
77
|
+
}
|
|
78
|
+
|
|
49
79
|
export function generateJustfile(name: string): string {
|
|
50
80
|
return `# Default recipe - list all available commands
|
|
51
81
|
default:
|
|
@@ -177,6 +207,7 @@ export function generateValidateCliTs(): string {
|
|
|
177
207
|
return `#!/usr/bin/env tsx
|
|
178
208
|
import { validate } from "./validate";
|
|
179
209
|
|
|
180
|
-
|
|
210
|
+
// \`validate\` takes an optional { basePath }; defaults to the lexicon root.
|
|
211
|
+
await validate();
|
|
181
212
|
`;
|
|
182
213
|
}
|
|
@@ -14,14 +14,15 @@ const CACHE_FILE = ".cache/schemas.zip";
|
|
|
14
14
|
*
|
|
15
15
|
* TODO: Point SCHEMA_URL at your real upstream schema source.
|
|
16
16
|
*/
|
|
17
|
-
export async function fetchSchemas(options?: { force?: boolean }): Promise<Map<string,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
cacheFile: CACHE_FILE,
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
export async function fetchSchemas(options?: { force?: boolean }): Promise<Map<string, Buffer>> {
|
|
18
|
+
// \`force\` is the second argument to fetchWithCache (not a FetchConfig field).
|
|
19
|
+
const zipData = await fetchWithCache(
|
|
20
|
+
{ url: SCHEMA_URL, cacheFile: CACHE_FILE },
|
|
21
|
+
options?.force,
|
|
22
|
+
);
|
|
23
23
|
|
|
24
|
-
// TODO: Adjust the filter to match your schema file names
|
|
24
|
+
// TODO: Adjust the filter to match your schema file names. extractFromZip yields
|
|
25
|
+
// Buffers — decode with \`.toString()\` in parse.ts as needed.
|
|
25
26
|
return extractFromZip(zipData, (name) => name.endsWith(".json"));
|
|
26
27
|
}
|
|
27
28
|
`;
|
|
@@ -232,6 +232,39 @@ describe("scaffold content validation", () => {
|
|
|
232
232
|
// AWS references
|
|
233
233
|
expect(content).toContain("lexicons/aws/");
|
|
234
234
|
});
|
|
235
|
+
|
|
236
|
+
// Drift guards — keep the scaffold compiling/installing against current core (#749).
|
|
237
|
+
test("package.json installs under plain npm and can build (#749)", () => {
|
|
238
|
+
const pkg = JSON.parse(readFileSync(join(targetDir, "package.json"), "utf-8"));
|
|
239
|
+
expect(JSON.stringify(pkg)).not.toContain("workspace:"); // rejected by plain npm
|
|
240
|
+
expect(pkg.devDependencies["@intentius/chant"]).toBe("*");
|
|
241
|
+
expect(pkg.dependencies).toBeUndefined();
|
|
242
|
+
expect(pkg.devDependencies["tsc-alias"]).toBeTruthy();
|
|
243
|
+
expect(pkg.scripts.build).toContain("tsconfig.build.json");
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
test("tsconfig.build.json uses bundler resolution + the development condition (#749)", () => {
|
|
247
|
+
const cfg = JSON.parse(readFileSync(join(targetDir, "tsconfig.build.json"), "utf-8"));
|
|
248
|
+
expect(cfg.compilerOptions.moduleResolution).toBe("bundler");
|
|
249
|
+
expect(cfg.compilerOptions.customConditions).toContain("development");
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
test("spec/fetch.ts matches fetchWithCache(config, force) → Map<string, Buffer> (#749)", () => {
|
|
253
|
+
const content = readFileSync(join(targetDir, "src/spec/fetch.ts"), "utf-8");
|
|
254
|
+
expect(content).toContain("Promise<Map<string, Buffer>>");
|
|
255
|
+
expect(content).not.toMatch(/force:\s*options/); // force is the 2nd arg, not a FetchConfig field
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
test("validate-cli.ts calls validate() with no verbose arg (#749)", () => {
|
|
259
|
+
const content = readFileSync(join(targetDir, "src/validate-cli.ts"), "utf-8");
|
|
260
|
+
expect(content).toContain("await validate();");
|
|
261
|
+
expect(content).not.toContain("verbose");
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
test("lint/rules/index.ts exports a `rules` array (plugin.ts imports it) (#749)", () => {
|
|
265
|
+
const content = readFileSync(join(targetDir, "src/lint/rules/index.ts"), "utf-8");
|
|
266
|
+
expect(content).toContain("export const rules");
|
|
267
|
+
});
|
|
235
268
|
});
|
|
236
269
|
|
|
237
270
|
// ── Fixture snapshot tests ──────────────────────────────────────────
|
|
@@ -8,7 +8,7 @@ import { generateCodegenGenerateTs, generateCodegenGenerateCliTs, generateCodege
|
|
|
8
8
|
import { generateSpecFetchTs, generateSpecParseTs } from "./init-lexicon/templates/spec";
|
|
9
9
|
import { generateSampleRuleTs, generateLintRulesIndexTs } from "./init-lexicon/templates/lint";
|
|
10
10
|
import { generateLspCompletionsTs, generateLspHoverTs } from "./init-lexicon/templates/lsp";
|
|
11
|
-
import { generatePackageJson, generateTsConfig, generateJustfile, generateGitignore, generateReadme, generateSerializerTs, generateValidateTs, generateValidateCliTs } from "./init-lexicon/templates/project";
|
|
11
|
+
import { generatePackageJson, generateTsConfig, generateTsConfigBuild, generateJustfile, generateGitignore, generateReadme, generateSerializerTs, generateValidateTs, generateValidateCliTs } from "./init-lexicon/templates/project";
|
|
12
12
|
import { generatePluginTestTs, generateSerializerTestTs, generateCompletionsTestTs, generateHoverTestTs } from "./init-lexicon/templates/tests";
|
|
13
13
|
import { generateDocsPackageJson, generateDocsTsConfig, generateDocsAstroConfig, generateDocsContentConfig, generateDocsIndexMdx } from "./init-lexicon/templates/docs";
|
|
14
14
|
import { generateExamplePackageJson, generateExampleInfraTs } from "./init-lexicon/templates/examples";
|
|
@@ -150,6 +150,7 @@ export async function initLexiconCommand(options: InitLexiconOptions): Promise<I
|
|
|
150
150
|
"src/validate-cli.ts": generateValidateCliTs(),
|
|
151
151
|
"package.json": generatePackageJson(name, names),
|
|
152
152
|
"tsconfig.json": generateTsConfig(),
|
|
153
|
+
"tsconfig.build.json": generateTsConfigBuild(),
|
|
153
154
|
"justfile": generateJustfile(name),
|
|
154
155
|
".gitignore": generateGitignore(),
|
|
155
156
|
"README.md": generateReadme(name, names),
|
package/src/yaml.test.ts
CHANGED
|
@@ -211,3 +211,36 @@ describe("parseScalar", () => {
|
|
|
211
211
|
expect(parseScalar("hello")).toBe("hello");
|
|
212
212
|
});
|
|
213
213
|
});
|
|
214
|
+
|
|
215
|
+
// Block scalars (#910) — round-trip parity with js-yaml for literal/folded/chomping,
|
|
216
|
+
// including block scalars nested inside array items (the case that mis-parsed).
|
|
217
|
+
describe("parseYAML block scalars (#910)", () => {
|
|
218
|
+
test("top-level literal | keeps newlines, clips to one trailing", () => {
|
|
219
|
+
expect(parseYAML("run: |\n line1\n line2\n")).toEqual({ run: "line1\nline2\n" });
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test("literal | nested inside a later array item (the reported bug)", () => {
|
|
223
|
+
expect(
|
|
224
|
+
parseYAML("steps:\n - name: first\n run: echo hi\n - name: second\n run: |\n line1\n line2\n"),
|
|
225
|
+
).toEqual({
|
|
226
|
+
steps: [
|
|
227
|
+
{ name: "first", run: "echo hi" },
|
|
228
|
+
{ name: "second", run: "line1\nline2\n" },
|
|
229
|
+
],
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
test("block scalar as an array item's first key, with a sibling key after", () => {
|
|
234
|
+
expect(parseYAML("steps:\n - run: |\n a\n b\n name: x\n")).toEqual({
|
|
235
|
+
steps: [{ run: "a\nb\n", name: "x" }],
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
test("strip |- drops the trailing newline; a sibling key after still parses", () => {
|
|
240
|
+
expect(parseYAML("a: |-\n x\n y\nb: 2\n")).toEqual({ a: "x\ny", b: 2 });
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
test("folded > folds line breaks to spaces, blank line to one newline", () => {
|
|
244
|
+
expect(parseYAML("msg: >\n a\n b\n\n c\n")).toEqual({ msg: "a b\nc\n" });
|
|
245
|
+
});
|
|
246
|
+
});
|
package/src/yaml.ts
CHANGED
|
@@ -155,6 +155,85 @@ export function parseYAML(content: string): Record<string, unknown> {
|
|
|
155
155
|
return parseYAMLLines(lines, 0, 0).value as Record<string, unknown>;
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
/**
|
|
159
|
+
* A block-scalar header: `|` (literal, keep newlines) or `>` (folded, newlines →
|
|
160
|
+
* spaces), with a chomping indicator (`-` strip trailing newlines, `+` keep them,
|
|
161
|
+
* default clip to a single one). Returns null when `inline` isn't a block header.
|
|
162
|
+
*/
|
|
163
|
+
interface BlockScalarHeader {
|
|
164
|
+
style: "literal" | "folded";
|
|
165
|
+
chomp: "clip" | "strip" | "keep";
|
|
166
|
+
}
|
|
167
|
+
function blockScalarHeader(inline: string): BlockScalarHeader | null {
|
|
168
|
+
const m = inline.match(/^([|>])([+-]?)(?:\s+#.*)?$/);
|
|
169
|
+
if (!m) return null;
|
|
170
|
+
return {
|
|
171
|
+
style: m[1] === "|" ? "literal" : "folded",
|
|
172
|
+
chomp: m[2] === "-" ? "strip" : m[2] === "+" ? "keep" : "clip",
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Parse a block scalar's body — the lines indented past `parentIndent`, dedented
|
|
178
|
+
* by the block's own indent (the first content line's). Handles literal/folded
|
|
179
|
+
* styles and clip/strip/keep chomping, matching js-yaml. Returns the string value
|
|
180
|
+
* and the index of the first line that is NOT part of the block.
|
|
181
|
+
*/
|
|
182
|
+
function parseBlockScalar(
|
|
183
|
+
lines: string[],
|
|
184
|
+
startIndex: number,
|
|
185
|
+
parentIndent: number,
|
|
186
|
+
header: BlockScalarHeader,
|
|
187
|
+
): { value: string; endIndex: number } {
|
|
188
|
+
const raw: string[] = [];
|
|
189
|
+
let blockIndent = -1;
|
|
190
|
+
let i = startIndex;
|
|
191
|
+
for (; i < lines.length; i++) {
|
|
192
|
+
const line = lines[i];
|
|
193
|
+
if (line.trim() === "") {
|
|
194
|
+
raw.push(""); // a blank line is part of the block (kept/chomped later)
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
const ni = line.search(/\S/);
|
|
198
|
+
if (ni <= parentIndent) break; // dedented out of the block
|
|
199
|
+
if (blockIndent === -1) blockIndent = ni;
|
|
200
|
+
if (ni < blockIndent) break;
|
|
201
|
+
raw.push(line.slice(blockIndent));
|
|
202
|
+
}
|
|
203
|
+
// Trailing blank lines belong to the block (chomping decides their fate).
|
|
204
|
+
let text: string;
|
|
205
|
+
if (header.style === "folded") {
|
|
206
|
+
// Fold each run of non-empty lines into a space-joined paragraph; a run of N
|
|
207
|
+
// blank lines between paragraphs becomes N newlines (a single blank → one
|
|
208
|
+
// newline), matching YAML folded semantics.
|
|
209
|
+
text = "";
|
|
210
|
+
let buf: string[] = [];
|
|
211
|
+
let blankRun = 0;
|
|
212
|
+
let wrote = false;
|
|
213
|
+
const flush = (): void => {
|
|
214
|
+
if (buf.length === 0) return;
|
|
215
|
+
if (wrote) text += "\n".repeat(blankRun);
|
|
216
|
+
text += buf.join(" ");
|
|
217
|
+
buf = [];
|
|
218
|
+
blankRun = 0;
|
|
219
|
+
wrote = true;
|
|
220
|
+
};
|
|
221
|
+
for (const l of raw) {
|
|
222
|
+
if (l === "") { flush(); blankRun++; }
|
|
223
|
+
else buf.push(l);
|
|
224
|
+
}
|
|
225
|
+
flush();
|
|
226
|
+
} else {
|
|
227
|
+
text = raw.join("\n");
|
|
228
|
+
}
|
|
229
|
+
const trailing = text.match(/\n*$/)?.[0].length ?? 0;
|
|
230
|
+
const stripped = text.replace(/\n+$/, "");
|
|
231
|
+
if (header.chomp === "strip") text = stripped;
|
|
232
|
+
else if (header.chomp === "keep") text = stripped + "\n".repeat(Math.max(trailing, raw.length > 0 ? 1 : 0));
|
|
233
|
+
else text = stripped === "" ? "" : stripped + "\n"; // clip
|
|
234
|
+
return { value: text, endIndex: i };
|
|
235
|
+
}
|
|
236
|
+
|
|
158
237
|
/**
|
|
159
238
|
* Parse indentation-based YAML lines into a key-value object.
|
|
160
239
|
*/
|
|
@@ -222,8 +301,15 @@ export function parseYAMLLines(
|
|
|
222
301
|
}
|
|
223
302
|
i++;
|
|
224
303
|
} else {
|
|
225
|
-
|
|
226
|
-
|
|
304
|
+
const header = blockScalarHeader(inlineValue);
|
|
305
|
+
if (header) {
|
|
306
|
+
const block = parseBlockScalar(lines, i + 1, indent, header);
|
|
307
|
+
result[key] = block.value;
|
|
308
|
+
i = block.endIndex;
|
|
309
|
+
} else {
|
|
310
|
+
result[key] = parseScalar(inlineValue);
|
|
311
|
+
i++;
|
|
312
|
+
}
|
|
227
313
|
}
|
|
228
314
|
} else if (line.trimStart().startsWith("- ")) {
|
|
229
315
|
break;
|
|
@@ -246,6 +332,15 @@ function parseArrayItemValue(
|
|
|
246
332
|
childIndent: number,
|
|
247
333
|
): unknown {
|
|
248
334
|
if (inlineValue !== "" && !inlineValue.startsWith("#")) {
|
|
335
|
+
const header = blockScalarHeader(inlineValue);
|
|
336
|
+
if (header) {
|
|
337
|
+
// Block scalar nested under an array-item key (e.g. `- name: x\n run: |`).
|
|
338
|
+
// The body is indented past the key's column. On a `- key: |` line the key
|
|
339
|
+
// sits 2 cols past the dash; on its own line it's the line's indent (#910).
|
|
340
|
+
const dash = lines[currentIndex].match(/^(\s*)- /);
|
|
341
|
+
const keyIndent = dash ? dash[1].length + 2 : lines[currentIndex].search(/\S/);
|
|
342
|
+
return parseBlockScalar(lines, currentIndex + 1, keyIndent, header).value;
|
|
343
|
+
}
|
|
249
344
|
if (inlineValue.startsWith("[")) {
|
|
250
345
|
try { return JSON.parse(inlineValue); } catch { return inlineValue; }
|
|
251
346
|
}
|
|
@@ -323,9 +418,13 @@ export function parseYAMLArray(
|
|
|
323
418
|
obj[kvMatch[1].trim()] = parseArrayItemValue(kvMatch[2].trim(), lines, i, indent + 2);
|
|
324
419
|
// Check for more keys at indent+2
|
|
325
420
|
const nextIndent = indent + 2;
|
|
326
|
-
|
|
421
|
+
const firstVal = kvMatch[2].trim();
|
|
422
|
+
let j = firstVal === "" || firstVal.startsWith("#")
|
|
327
423
|
? skipNestedBlock(lines, i + 1, nextIndent)
|
|
328
|
-
:
|
|
424
|
+
: blockScalarHeader(firstVal)
|
|
425
|
+
// Block body is indented past the key (nextIndent); skip it (#910).
|
|
426
|
+
? skipNestedBlock(lines, i + 1, nextIndent + 1)
|
|
427
|
+
: i + 1;
|
|
329
428
|
while (j < lines.length) {
|
|
330
429
|
const nextLine = lines[j];
|
|
331
430
|
if (nextLine.trim() === "" || nextLine.trim().startsWith("#")) {
|
|
@@ -341,6 +440,9 @@ export function parseYAMLArray(
|
|
|
341
440
|
obj[nextKV[2].trim()] = parseArrayItemValue(nextVal, lines, j, ni + 2);
|
|
342
441
|
if (nextVal === "" || nextVal.startsWith("#")) {
|
|
343
442
|
j = skipNestedBlock(lines, j + 1, ni + 2);
|
|
443
|
+
} else if (blockScalarHeader(nextVal)) {
|
|
444
|
+
// Skip the block body (indented past this key at `ni`) (#910).
|
|
445
|
+
j = skipNestedBlock(lines, j + 1, ni + 1);
|
|
344
446
|
} else {
|
|
345
447
|
j++;
|
|
346
448
|
}
|