@intentius/chant 0.0.1
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 +365 -0
- package/package.json +22 -0
- package/src/attrref.test.ts +148 -0
- package/src/attrref.ts +50 -0
- package/src/barrel.test.ts +157 -0
- package/src/barrel.ts +101 -0
- package/src/bench.test.ts +227 -0
- package/src/build.test.ts +437 -0
- package/src/build.ts +425 -0
- package/src/builder.test.ts +312 -0
- package/src/builder.ts +56 -0
- package/src/child-project.ts +44 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/README.md +26 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/docs/astro.config.mjs +14 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/docs/package.json +16 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/docs/src/content/docs/index.mdx +8 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/docs/src/content.config.ts +7 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/docs/tsconfig.json +10 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/examples/getting-started/.gitkeep +0 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/justfile +26 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +29 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/docs.ts +25 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/generate-cli.ts +8 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/generate.ts +74 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/naming.ts +33 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/package.ts +25 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/rollback.ts +45 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/coverage.ts +11 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/generated/.gitkeep +0 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/import/generator.ts +10 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/import/parser.ts +10 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/index.ts +9 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/lint/rules/index.ts +1 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/lint/rules/sample.ts +18 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/lsp/completions.ts +14 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/lsp/hover.ts +14 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/plugin.ts +110 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/serializer.ts +24 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/spec/fetch.ts +21 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/spec/parse.ts +25 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/validate-cli.ts +4 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/validate.ts +24 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/tsconfig.json +10 -0
- package/src/cli/commands/__fixtures__/sample-rule.ts +11 -0
- package/src/cli/commands/__snapshots__/init-lexicon.test.ts.snap +222 -0
- package/src/cli/commands/build.test.ts +149 -0
- package/src/cli/commands/build.ts +344 -0
- package/src/cli/commands/diff.test.ts +148 -0
- package/src/cli/commands/diff.ts +221 -0
- package/src/cli/commands/doctor.test.ts +239 -0
- package/src/cli/commands/doctor.ts +224 -0
- package/src/cli/commands/import.test.ts +379 -0
- package/src/cli/commands/import.ts +335 -0
- package/src/cli/commands/init-lexicon.test.ts +297 -0
- package/src/cli/commands/init-lexicon.ts +993 -0
- package/src/cli/commands/init.test.ts +317 -0
- package/src/cli/commands/init.ts +505 -0
- package/src/cli/commands/licenses.ts +165 -0
- package/src/cli/commands/lint.test.ts +332 -0
- package/src/cli/commands/lint.ts +408 -0
- package/src/cli/commands/list.test.ts +100 -0
- package/src/cli/commands/list.ts +108 -0
- package/src/cli/commands/update.test.ts +38 -0
- package/src/cli/commands/update.ts +207 -0
- package/src/cli/conflict-check.test.ts +255 -0
- package/src/cli/conflict-check.ts +89 -0
- package/src/cli/debug.ts +8 -0
- package/src/cli/format.test.ts +140 -0
- package/src/cli/format.ts +133 -0
- package/src/cli/handlers/build.ts +58 -0
- package/src/cli/handlers/dev.ts +38 -0
- package/src/cli/handlers/init.ts +46 -0
- package/src/cli/handlers/lint.ts +36 -0
- package/src/cli/handlers/misc.ts +57 -0
- package/src/cli/handlers/serve.ts +26 -0
- package/src/cli/index.ts +3 -0
- package/src/cli/lsp/capabilities.ts +46 -0
- package/src/cli/lsp/diagnostics.ts +52 -0
- package/src/cli/lsp/server.test.ts +618 -0
- package/src/cli/lsp/server.ts +393 -0
- package/src/cli/main.test.ts +257 -0
- package/src/cli/main.ts +224 -0
- package/src/cli/mcp/resources/context.ts +59 -0
- package/src/cli/mcp/server.test.ts +747 -0
- package/src/cli/mcp/server.ts +402 -0
- package/src/cli/mcp/tools/build.ts +117 -0
- package/src/cli/mcp/tools/import.ts +48 -0
- package/src/cli/mcp/tools/lint.ts +45 -0
- package/src/cli/plugins.test.ts +31 -0
- package/src/cli/plugins.ts +94 -0
- package/src/cli/registry.ts +73 -0
- package/src/cli/reporters/stylish.test.ts +282 -0
- package/src/cli/reporters/stylish.ts +186 -0
- package/src/cli/watch.test.ts +81 -0
- package/src/cli/watch.ts +101 -0
- package/src/codegen/case.test.ts +30 -0
- package/src/codegen/case.ts +11 -0
- package/src/codegen/coverage.ts +167 -0
- package/src/codegen/docs.ts +634 -0
- package/src/codegen/fetch.test.ts +119 -0
- package/src/codegen/fetch.ts +261 -0
- package/src/codegen/generate-registry.test.ts +118 -0
- package/src/codegen/generate-registry.ts +107 -0
- package/src/codegen/generate-runtime-index.test.ts +81 -0
- package/src/codegen/generate-runtime-index.ts +99 -0
- package/src/codegen/generate-typescript.test.ts +146 -0
- package/src/codegen/generate-typescript.ts +161 -0
- package/src/codegen/generate.ts +206 -0
- package/src/codegen/json-patch.test.ts +113 -0
- package/src/codegen/json-patch.ts +151 -0
- package/src/codegen/json-schema.test.ts +196 -0
- package/src/codegen/json-schema.ts +209 -0
- package/src/codegen/naming.ts +201 -0
- package/src/codegen/package.ts +161 -0
- package/src/codegen/rollback.test.ts +92 -0
- package/src/codegen/rollback.ts +115 -0
- package/src/codegen/topo-sort.test.ts +69 -0
- package/src/codegen/topo-sort.ts +46 -0
- package/src/codegen/typecheck.test.ts +37 -0
- package/src/codegen/typecheck.ts +74 -0
- package/src/codegen/validate.test.ts +86 -0
- package/src/codegen/validate.ts +143 -0
- package/src/composite.test.ts +426 -0
- package/src/composite.ts +243 -0
- package/src/config.test.ts +91 -0
- package/src/config.ts +87 -0
- package/src/declarable.test.ts +160 -0
- package/src/declarable.ts +47 -0
- package/src/detectLexicon.test.ts +236 -0
- package/src/detectLexicon.ts +37 -0
- package/src/discovery/cache.test.ts +78 -0
- package/src/discovery/cache.ts +86 -0
- package/src/discovery/collect.test.ts +269 -0
- package/src/discovery/collect.ts +51 -0
- package/src/discovery/cycles.test.ts +238 -0
- package/src/discovery/cycles.ts +107 -0
- package/src/discovery/files.test.ts +154 -0
- package/src/discovery/files.ts +61 -0
- package/src/discovery/graph.test.ts +476 -0
- package/src/discovery/graph.ts +150 -0
- package/src/discovery/import.test.ts +199 -0
- package/src/discovery/import.ts +20 -0
- package/src/discovery/index.test.ts +272 -0
- package/src/discovery/index.ts +132 -0
- package/src/discovery/resolve.test.ts +267 -0
- package/src/discovery/resolve.ts +54 -0
- package/src/errors.test.ts +138 -0
- package/src/errors.ts +86 -0
- package/src/import/base-parser.test.ts +67 -0
- package/src/import/base-parser.ts +48 -0
- package/src/import/generator.ts +21 -0
- package/src/import/ir-utils.test.ts +103 -0
- package/src/import/ir-utils.ts +87 -0
- package/src/import/parser.ts +41 -0
- package/src/index.ts +60 -0
- package/src/intrinsic-interpolation.test.ts +91 -0
- package/src/intrinsic-interpolation.ts +89 -0
- package/src/intrinsic.test.ts +69 -0
- package/src/intrinsic.ts +43 -0
- package/src/lexicon-integrity.test.ts +94 -0
- package/src/lexicon-integrity.ts +69 -0
- package/src/lexicon-manifest.test.ts +101 -0
- package/src/lexicon-manifest.ts +71 -0
- package/src/lexicon-output.test.ts +182 -0
- package/src/lexicon-output.ts +82 -0
- package/src/lexicon-schema.test.ts +239 -0
- package/src/lexicon-schema.ts +144 -0
- package/src/lexicon.ts +212 -0
- package/src/lint/config-overrides.test.ts +254 -0
- package/src/lint/config.test.ts +644 -0
- package/src/lint/config.ts +375 -0
- package/src/lint/declarative.test.ts +256 -0
- package/src/lint/declarative.ts +187 -0
- package/src/lint/engine.test.ts +465 -0
- package/src/lint/engine.ts +172 -0
- package/src/lint/named-checks.test.ts +37 -0
- package/src/lint/named-checks.ts +33 -0
- package/src/lint/parser.test.ts +129 -0
- package/src/lint/parser.ts +42 -0
- package/src/lint/post-synth.test.ts +113 -0
- package/src/lint/post-synth.ts +76 -0
- package/src/lint/presets/relaxed.json +19 -0
- package/src/lint/presets/strict.json +19 -0
- package/src/lint/rule-loader.test.ts +67 -0
- package/src/lint/rule-loader.ts +67 -0
- package/src/lint/rule-options.test.ts +141 -0
- package/src/lint/rule.test.ts +196 -0
- package/src/lint/rule.ts +98 -0
- package/src/lint/rules/barrel-import-style.test.ts +80 -0
- package/src/lint/rules/barrel-import-style.ts +59 -0
- package/src/lint/rules/composite-scope.ts +55 -0
- package/src/lint/rules/cor017-composite-name-match.test.ts +107 -0
- package/src/lint/rules/cor017-composite-name-match.ts +108 -0
- package/src/lint/rules/cor018-composite-prefer-lexicon-type.test.ts +172 -0
- package/src/lint/rules/cor018-composite-prefer-lexicon-type.ts +167 -0
- package/src/lint/rules/declarable-naming-convention.test.ts +69 -0
- package/src/lint/rules/declarable-naming-convention.ts +70 -0
- package/src/lint/rules/enforce-barrel-import.test.ts +169 -0
- package/src/lint/rules/enforce-barrel-import.ts +81 -0
- package/src/lint/rules/enforce-barrel-ref.test.ts +114 -0
- package/src/lint/rules/enforce-barrel-ref.ts +75 -0
- package/src/lint/rules/evl001-non-literal-expression.test.ts +158 -0
- package/src/lint/rules/evl001-non-literal-expression.ts +149 -0
- package/src/lint/rules/evl002-control-flow-resource.test.ts +110 -0
- package/src/lint/rules/evl002-control-flow-resource.ts +61 -0
- package/src/lint/rules/evl003-dynamic-property-access.test.ts +63 -0
- package/src/lint/rules/evl003-dynamic-property-access.ts +41 -0
- package/src/lint/rules/evl004-spread-non-const.test.ts +130 -0
- package/src/lint/rules/evl004-spread-non-const.ts +111 -0
- package/src/lint/rules/evl005-resource-block-body.test.ts +59 -0
- package/src/lint/rules/evl005-resource-block-body.ts +49 -0
- package/src/lint/rules/evl006-barrel-usage.test.ts +63 -0
- package/src/lint/rules/evl006-barrel-usage.ts +95 -0
- package/src/lint/rules/evl007-invalid-siblings.test.ts +87 -0
- package/src/lint/rules/evl007-invalid-siblings.ts +139 -0
- package/src/lint/rules/evl008-unresolvable-barrel-ref.test.ts +118 -0
- package/src/lint/rules/evl008-unresolvable-barrel-ref.ts +140 -0
- package/src/lint/rules/evl009-composite-no-constant.test.ts +162 -0
- package/src/lint/rules/evl009-composite-no-constant.ts +171 -0
- package/src/lint/rules/evl010-composite-no-transform.test.ts +121 -0
- package/src/lint/rules/evl010-composite-no-transform.ts +69 -0
- package/src/lint/rules/export-required.test.ts +213 -0
- package/src/lint/rules/export-required.ts +158 -0
- package/src/lint/rules/file-declarable-limit.test.ts +148 -0
- package/src/lint/rules/file-declarable-limit.ts +96 -0
- package/src/lint/rules/flat-declarations.test.ts +210 -0
- package/src/lint/rules/flat-declarations.ts +70 -0
- package/src/lint/rules/index.ts +99 -0
- package/src/lint/rules/no-cyclic-declarable-ref.test.ts +135 -0
- package/src/lint/rules/no-cyclic-declarable-ref.ts +178 -0
- package/src/lint/rules/no-redundant-type-import.test.ts +129 -0
- package/src/lint/rules/no-redundant-type-import.ts +85 -0
- package/src/lint/rules/no-redundant-value-cast.test.ts +51 -0
- package/src/lint/rules/no-redundant-value-cast.ts +46 -0
- package/src/lint/rules/no-string-ref.test.ts +100 -0
- package/src/lint/rules/no-string-ref.ts +66 -0
- package/src/lint/rules/no-unused-declarable-import.test.ts +74 -0
- package/src/lint/rules/no-unused-declarable-import.ts +103 -0
- package/src/lint/rules/no-unused-declarable.test.ts +134 -0
- package/src/lint/rules/no-unused-declarable.ts +118 -0
- package/src/lint/rules/prefer-namespace-import.test.ts +102 -0
- package/src/lint/rules/prefer-namespace-import.ts +63 -0
- package/src/lint/rules/single-concern-file.test.ts +156 -0
- package/src/lint/rules/single-concern-file.ts +98 -0
- package/src/lint/rules/stale-barrel-types.ts +60 -0
- package/src/lint/selectors.test.ts +113 -0
- package/src/lint/selectors.ts +188 -0
- package/src/lsp/lexicon-providers.ts +191 -0
- package/src/lsp/types.ts +79 -0
- package/src/mcp/types.ts +22 -0
- package/src/project/scan.test.ts +178 -0
- package/src/project/scan.ts +182 -0
- package/src/project/sync.test.ts +87 -0
- package/src/project/sync.ts +46 -0
- package/src/project-validation.test.ts +64 -0
- package/src/project-validation.ts +79 -0
- package/src/pseudo-parameter.test.ts +39 -0
- package/src/pseudo-parameter.ts +47 -0
- package/src/runtime.ts +68 -0
- package/src/serializer-walker.test.ts +124 -0
- package/src/serializer-walker.ts +83 -0
- package/src/serializer.ts +42 -0
- package/src/sort.test.ts +290 -0
- package/src/sort.ts +58 -0
- package/src/stack-output.ts +82 -0
- package/src/types.test.ts +307 -0
- package/src/types.ts +46 -0
- package/src/utils.test.ts +195 -0
- package/src/utils.ts +46 -0
- package/src/validation.test.ts +308 -0
- package/src/validation.ts +50 -0
|
@@ -0,0 +1,634 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic documentation pipeline for lexicons.
|
|
3
|
+
*
|
|
4
|
+
* Reads manifest.json and meta.json from a packaged lexicon's dist/ directory,
|
|
5
|
+
* collects rule metadata from source, and generates structured MDX reference
|
|
6
|
+
* pages. Individual lexicons supply callbacks for provider-specific formatting
|
|
7
|
+
* (service grouping, resource type URLs, custom overview content).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { readFileSync, readdirSync, writeFileSync, mkdirSync, rmSync } from "fs";
|
|
11
|
+
import { join } from "path";
|
|
12
|
+
|
|
13
|
+
// ── Types ──────────────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
export interface DocsConfig {
|
|
16
|
+
/** Lexicon name (used for page titles and paths) */
|
|
17
|
+
name: string;
|
|
18
|
+
/** Display name (e.g. "AWS CloudFormation") */
|
|
19
|
+
displayName: string;
|
|
20
|
+
/** Short description of what this lexicon targets */
|
|
21
|
+
description: string;
|
|
22
|
+
/** Path to dist/ directory containing manifest.json and meta.json */
|
|
23
|
+
distDir: string;
|
|
24
|
+
/** Output directory for generated .mdx files */
|
|
25
|
+
outDir: string;
|
|
26
|
+
/** Lexicon-specific overview content (markdown) */
|
|
27
|
+
overview?: string;
|
|
28
|
+
/** Output format description (e.g. "CloudFormation JSON template") */
|
|
29
|
+
outputFormat?: string;
|
|
30
|
+
/** Custom service grouping from resource type (e.g. "AWS::S3::Bucket" → "S3") */
|
|
31
|
+
serviceFromType?: (resourceType: string) => string;
|
|
32
|
+
/** Custom sections to append to overview page */
|
|
33
|
+
extraSections?: Array<{ title: string; content: string }>;
|
|
34
|
+
/** Standalone pages added to the sidebar after Overview */
|
|
35
|
+
extraPages?: Array<{ slug: string; title: string; description?: string; content: string }>;
|
|
36
|
+
/** Slugs of auto-generated pages to suppress (e.g. "pseudo-parameters") */
|
|
37
|
+
suppressPages?: string[];
|
|
38
|
+
/** Source directory for scanning rule files (defaults to srcDir sibling of distDir) */
|
|
39
|
+
srcDir?: string;
|
|
40
|
+
/** Base path for the generated Astro site (e.g. '/lexicons/aws/') */
|
|
41
|
+
basePath?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface DocsResult {
|
|
45
|
+
pages: Map<string, string>;
|
|
46
|
+
stats: {
|
|
47
|
+
resources: number;
|
|
48
|
+
properties: number;
|
|
49
|
+
services: number;
|
|
50
|
+
rules: number;
|
|
51
|
+
intrinsics: number;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface ManifestJSON {
|
|
56
|
+
name: string;
|
|
57
|
+
version: string;
|
|
58
|
+
namespace?: string;
|
|
59
|
+
intrinsics?: Array<{
|
|
60
|
+
name: string;
|
|
61
|
+
description?: string;
|
|
62
|
+
outputKey?: string;
|
|
63
|
+
isTag?: boolean;
|
|
64
|
+
}>;
|
|
65
|
+
pseudoParameters?: Record<string, string>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface MetaEntry {
|
|
69
|
+
resourceType: string;
|
|
70
|
+
kind: "resource" | "property";
|
|
71
|
+
lexicon: string;
|
|
72
|
+
attrs?: Record<string, string>;
|
|
73
|
+
propertyConstraints?: Record<string, unknown>;
|
|
74
|
+
createOnly?: string[];
|
|
75
|
+
writeOnly?: string[];
|
|
76
|
+
primaryIdentifier?: string[];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
interface RuleMeta {
|
|
80
|
+
id: string;
|
|
81
|
+
severity: string;
|
|
82
|
+
category: string;
|
|
83
|
+
description: string;
|
|
84
|
+
type: "lint" | "post-synth";
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ── Pipeline ───────────────────────────────────────────────────────
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Run the documentation pipeline with the supplied config.
|
|
91
|
+
*/
|
|
92
|
+
export function docsPipeline(config: DocsConfig): DocsResult {
|
|
93
|
+
const manifest = JSON.parse(
|
|
94
|
+
readFileSync(join(config.distDir, "manifest.json"), "utf-8"),
|
|
95
|
+
) as ManifestJSON;
|
|
96
|
+
|
|
97
|
+
const meta = JSON.parse(
|
|
98
|
+
readFileSync(join(config.distDir, "meta.json"), "utf-8"),
|
|
99
|
+
) as Record<string, MetaEntry>;
|
|
100
|
+
|
|
101
|
+
const rules = scanRules(config.srcDir ?? join(config.distDir, "..", "src"));
|
|
102
|
+
|
|
103
|
+
// Separate resources and properties
|
|
104
|
+
const resources = new Map<string, MetaEntry>();
|
|
105
|
+
const properties = new Map<string, MetaEntry>();
|
|
106
|
+
for (const [className, entry] of Object.entries(meta)) {
|
|
107
|
+
if (entry.kind === "resource") {
|
|
108
|
+
resources.set(className, entry);
|
|
109
|
+
} else {
|
|
110
|
+
properties.set(className, entry);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Group resources by service
|
|
115
|
+
const serviceFromType =
|
|
116
|
+
config.serviceFromType ?? ((t: string) => t.split("::")[1] ?? "Other");
|
|
117
|
+
const serviceGroups = new Map<string, Map<string, MetaEntry>>();
|
|
118
|
+
for (const [className, entry] of resources) {
|
|
119
|
+
const service = serviceFromType(entry.resourceType);
|
|
120
|
+
let group = serviceGroups.get(service);
|
|
121
|
+
if (!group) {
|
|
122
|
+
group = new Map();
|
|
123
|
+
serviceGroups.set(service, group);
|
|
124
|
+
}
|
|
125
|
+
group.set(className, entry);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Generate pages
|
|
129
|
+
const pages = new Map<string, string>();
|
|
130
|
+
|
|
131
|
+
pages.set(
|
|
132
|
+
"index.mdx",
|
|
133
|
+
generateOverview(config, manifest, resources, properties, serviceGroups, rules),
|
|
134
|
+
);
|
|
135
|
+
const suppress = new Set(config.suppressPages ?? []);
|
|
136
|
+
|
|
137
|
+
// Extra pages from lexicon config
|
|
138
|
+
if (config.extraPages) {
|
|
139
|
+
for (const page of config.extraPages) {
|
|
140
|
+
pages.set(
|
|
141
|
+
`${page.slug}.mdx`,
|
|
142
|
+
[
|
|
143
|
+
"---",
|
|
144
|
+
`title: "${page.title}"`,
|
|
145
|
+
page.description ? `description: "${page.description}"` : "",
|
|
146
|
+
"---",
|
|
147
|
+
"",
|
|
148
|
+
page.content,
|
|
149
|
+
"",
|
|
150
|
+
]
|
|
151
|
+
.filter(Boolean)
|
|
152
|
+
.join("\n"),
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (!suppress.has("intrinsics") && manifest.intrinsics && manifest.intrinsics.length > 0) {
|
|
158
|
+
pages.set("intrinsics.mdx", generateIntrinsics(config, manifest));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (
|
|
162
|
+
!suppress.has("pseudo-parameters") &&
|
|
163
|
+
manifest.pseudoParameters &&
|
|
164
|
+
Object.keys(manifest.pseudoParameters).length > 0
|
|
165
|
+
) {
|
|
166
|
+
pages.set(
|
|
167
|
+
"pseudo-parameters.mdx",
|
|
168
|
+
generatePseudoParameters(config, manifest),
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (!suppress.has("rules") && rules.length > 0) {
|
|
173
|
+
pages.set("rules.mdx", generateRules(config, rules));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (!suppress.has("serialization")) {
|
|
177
|
+
pages.set("serialization.mdx", generateSerialization(config));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return {
|
|
181
|
+
pages,
|
|
182
|
+
stats: {
|
|
183
|
+
resources: resources.size,
|
|
184
|
+
properties: properties.size,
|
|
185
|
+
services: serviceGroups.size,
|
|
186
|
+
rules: rules.length,
|
|
187
|
+
intrinsics: manifest.intrinsics?.length ?? 0,
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Write generated docs pages to disk.
|
|
194
|
+
*/
|
|
195
|
+
export function writeDocsPages(result: DocsResult, outDir: string): void {
|
|
196
|
+
mkdirSync(outDir, { recursive: true });
|
|
197
|
+
for (const [filename, content] of result.pages) {
|
|
198
|
+
const filePath = join(outDir, filename);
|
|
199
|
+
const dir = filePath.substring(0, filePath.lastIndexOf("/"));
|
|
200
|
+
mkdirSync(dir, { recursive: true });
|
|
201
|
+
writeFileSync(filePath, content);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Scaffold a standalone Starlight docs site from pipeline results.
|
|
207
|
+
*
|
|
208
|
+
* Writes: package.json, astro.config.mjs, tsconfig.json, and all content
|
|
209
|
+
* pages under src/content/docs/. The resulting directory can be built with
|
|
210
|
+
* `bun install && bun run build`.
|
|
211
|
+
*/
|
|
212
|
+
export function writeDocsSite(config: DocsConfig, result: DocsResult): void {
|
|
213
|
+
const outDir = config.outDir;
|
|
214
|
+
const contentDir = join(outDir, "src", "content", "docs");
|
|
215
|
+
|
|
216
|
+
// Clear stale content and Astro caches so changes are picked up on next build
|
|
217
|
+
rmSync(contentDir, { recursive: true, force: true });
|
|
218
|
+
rmSync(join(outDir, ".astro"), { recursive: true, force: true });
|
|
219
|
+
rmSync(join(outDir, "node_modules", ".astro"), { recursive: true, force: true });
|
|
220
|
+
|
|
221
|
+
// Write content pages
|
|
222
|
+
writeDocsPages(result, contentDir);
|
|
223
|
+
|
|
224
|
+
// Build sidebar from generated pages
|
|
225
|
+
const sidebar = buildSidebar(config, result);
|
|
226
|
+
|
|
227
|
+
// package.json
|
|
228
|
+
writeFileSync(
|
|
229
|
+
join(outDir, "package.json"),
|
|
230
|
+
JSON.stringify(
|
|
231
|
+
{
|
|
232
|
+
name: `@intentius/chant-lexicon-${config.name}-docs`,
|
|
233
|
+
type: "module",
|
|
234
|
+
version: "0.0.1",
|
|
235
|
+
private: true,
|
|
236
|
+
scripts: {
|
|
237
|
+
dev: "astro dev",
|
|
238
|
+
build: "astro build",
|
|
239
|
+
preview: "astro preview",
|
|
240
|
+
},
|
|
241
|
+
dependencies: {
|
|
242
|
+
"@astrojs/starlight": "^0.37.6",
|
|
243
|
+
astro: "^5.6.1",
|
|
244
|
+
sharp: "^0.34.2",
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
null,
|
|
248
|
+
2,
|
|
249
|
+
) + "\n",
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
// tsconfig.json
|
|
253
|
+
writeFileSync(
|
|
254
|
+
join(outDir, "tsconfig.json"),
|
|
255
|
+
JSON.stringify(
|
|
256
|
+
{
|
|
257
|
+
extends: "astro/tsconfigs/strict",
|
|
258
|
+
include: [".astro/types.d.ts", "**/*"],
|
|
259
|
+
exclude: ["dist"],
|
|
260
|
+
},
|
|
261
|
+
null,
|
|
262
|
+
2,
|
|
263
|
+
) + "\n",
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
// src/content.config.ts (required by Astro 5+ / Starlight 0.37+)
|
|
267
|
+
mkdirSync(join(outDir, "src"), { recursive: true });
|
|
268
|
+
writeFileSync(
|
|
269
|
+
join(outDir, "src", "content.config.ts"),
|
|
270
|
+
`import { defineCollection } from 'astro:content';
|
|
271
|
+
import { docsLoader } from '@astrojs/starlight/loaders';
|
|
272
|
+
import { docsSchema } from '@astrojs/starlight/schema';
|
|
273
|
+
|
|
274
|
+
export const collections = {
|
|
275
|
+
docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
|
|
276
|
+
};
|
|
277
|
+
`,
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
// astro.config.mjs
|
|
281
|
+
writeFileSync(
|
|
282
|
+
join(outDir, "astro.config.mjs"),
|
|
283
|
+
`// @ts-check
|
|
284
|
+
import { defineConfig } from 'astro/config';
|
|
285
|
+
import starlight from '@astrojs/starlight';
|
|
286
|
+
|
|
287
|
+
export default defineConfig({${config.basePath ? `\n base: '${config.basePath}',` : ""}
|
|
288
|
+
integrations: [
|
|
289
|
+
starlight({
|
|
290
|
+
title: '${config.displayName}',
|
|
291
|
+
sidebar: ${JSON.stringify(sidebar, null, 6).replace(/\n/g, "\n ")},
|
|
292
|
+
}),
|
|
293
|
+
],
|
|
294
|
+
});
|
|
295
|
+
`,
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function buildSidebar(
|
|
300
|
+
config: DocsConfig,
|
|
301
|
+
result: DocsResult,
|
|
302
|
+
): Array<Record<string, unknown>> {
|
|
303
|
+
const items: Array<Record<string, unknown>> = [
|
|
304
|
+
{ label: "Overview", slug: "index" },
|
|
305
|
+
];
|
|
306
|
+
|
|
307
|
+
const suppress = new Set(config.suppressPages ?? []);
|
|
308
|
+
const extraSlugs = new Set((config.extraPages ?? []).map((p) => p.slug));
|
|
309
|
+
|
|
310
|
+
// Extra pages from lexicon config (appear after Overview)
|
|
311
|
+
if (config.extraPages) {
|
|
312
|
+
for (const page of config.extraPages) {
|
|
313
|
+
items.push({ label: page.title, slug: page.slug });
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (!suppress.has("intrinsics") && !extraSlugs.has("intrinsics") && result.pages.has("intrinsics.mdx")) {
|
|
318
|
+
items.push({ label: "Intrinsics", slug: "intrinsics" });
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (!suppress.has("pseudo-parameters") && !extraSlugs.has("pseudo-parameters") && result.pages.has("pseudo-parameters.mdx")) {
|
|
322
|
+
items.push({ label: "Pseudo-Parameters", slug: "pseudo-parameters" });
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (!suppress.has("rules") && !extraSlugs.has("rules") && result.pages.has("rules.mdx")) {
|
|
326
|
+
items.push({ label: "Lint Rules", slug: "rules" });
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (!suppress.has("serialization") && !extraSlugs.has("serialization") && result.pages.has("serialization.mdx")) {
|
|
330
|
+
items.push({ label: "Serialization", slug: "serialization" });
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return items;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// ── Page generators ────────────────────────────────────────────────
|
|
337
|
+
|
|
338
|
+
function generateOverview(
|
|
339
|
+
config: DocsConfig,
|
|
340
|
+
manifest: ManifestJSON,
|
|
341
|
+
resources: Map<string, MetaEntry>,
|
|
342
|
+
properties: Map<string, MetaEntry>,
|
|
343
|
+
serviceGroups: Map<string, Map<string, MetaEntry>>,
|
|
344
|
+
rules: RuleMeta[],
|
|
345
|
+
): string {
|
|
346
|
+
const lines: string[] = [
|
|
347
|
+
"---",
|
|
348
|
+
`title: "${config.displayName}"`,
|
|
349
|
+
`description: "${config.description}"`,
|
|
350
|
+
"---",
|
|
351
|
+
"",
|
|
352
|
+
config.overview ?? `Reference documentation for the **${config.displayName}** lexicon.`,
|
|
353
|
+
"",
|
|
354
|
+
"## At a Glance",
|
|
355
|
+
"",
|
|
356
|
+
`| Metric | Count |`,
|
|
357
|
+
`|--------|-------|`,
|
|
358
|
+
`| Resources | ${resources.size} |`,
|
|
359
|
+
`| Property types | ${properties.size} |`,
|
|
360
|
+
`| Services | ${serviceGroups.size} |`,
|
|
361
|
+
`| Intrinsic functions | ${manifest.intrinsics?.length ?? 0} |`,
|
|
362
|
+
`| Pseudo-parameters | ${Object.keys(manifest.pseudoParameters ?? {}).length} |`,
|
|
363
|
+
`| Lint rules | ${rules.length} |`,
|
|
364
|
+
"",
|
|
365
|
+
`**Lexicon version:** ${manifest.version} `,
|
|
366
|
+
`**Namespace:** \`${manifest.namespace ?? manifest.name}\``,
|
|
367
|
+
"",
|
|
368
|
+
];
|
|
369
|
+
|
|
370
|
+
const suppress = new Set(config.suppressPages ?? []);
|
|
371
|
+
|
|
372
|
+
// Extra pages listed first in reference links
|
|
373
|
+
if (config.extraPages && config.extraPages.length > 0) {
|
|
374
|
+
for (const page of config.extraPages) {
|
|
375
|
+
lines.push(`- [${page.title}](./${page.slug})`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (!suppress.has("intrinsics") && manifest.intrinsics && manifest.intrinsics.length > 0) {
|
|
380
|
+
lines.push(
|
|
381
|
+
`- [Intrinsic Functions](./intrinsics) — ${manifest.intrinsics.length} built-in functions`,
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
if (
|
|
385
|
+
!suppress.has("pseudo-parameters") &&
|
|
386
|
+
manifest.pseudoParameters &&
|
|
387
|
+
Object.keys(manifest.pseudoParameters).length > 0
|
|
388
|
+
) {
|
|
389
|
+
lines.push(
|
|
390
|
+
`- [Pseudo-Parameters](./pseudo-parameters) — ${Object.keys(manifest.pseudoParameters).length} pseudo-parameters`,
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
if (!suppress.has("rules") && rules.length > 0) {
|
|
394
|
+
lines.push(`- [Lint Rules](./rules) — ${rules.length} rules`);
|
|
395
|
+
}
|
|
396
|
+
if (!suppress.has("serialization")) {
|
|
397
|
+
lines.push(`- [Serialization](./serialization) — output format details`);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (config.extraSections) {
|
|
401
|
+
for (const section of config.extraSections) {
|
|
402
|
+
lines.push("", `## ${section.title}`, "", section.content);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
lines.push("");
|
|
407
|
+
return lines.join("\n");
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function generateIntrinsics(
|
|
411
|
+
config: DocsConfig,
|
|
412
|
+
manifest: ManifestJSON,
|
|
413
|
+
): string {
|
|
414
|
+
const intrinsics = manifest.intrinsics!;
|
|
415
|
+
const lines: string[] = [
|
|
416
|
+
"---",
|
|
417
|
+
`title: "Intrinsic Functions"`,
|
|
418
|
+
`description: "Built-in intrinsic functions for the ${config.displayName} lexicon"`,
|
|
419
|
+
"---",
|
|
420
|
+
"",
|
|
421
|
+
`The ${config.displayName} lexicon provides **${intrinsics.length}** intrinsic functions.`,
|
|
422
|
+
"",
|
|
423
|
+
"| Function | Description | Output Key | Tag? |",
|
|
424
|
+
"|----------|-------------|------------|------|",
|
|
425
|
+
];
|
|
426
|
+
|
|
427
|
+
for (const fn of intrinsics) {
|
|
428
|
+
const tag = fn.isTag ? "Yes" : "No";
|
|
429
|
+
lines.push(
|
|
430
|
+
`| \`${fn.name}\` | ${fn.description ?? "—"} | \`${fn.outputKey ?? fn.name}\` | ${tag} |`,
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
lines.push("");
|
|
435
|
+
return lines.join("\n");
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
function generatePseudoParameters(
|
|
439
|
+
config: DocsConfig,
|
|
440
|
+
manifest: ManifestJSON,
|
|
441
|
+
): string {
|
|
442
|
+
const params = manifest.pseudoParameters!;
|
|
443
|
+
const entries = Object.entries(params);
|
|
444
|
+
const lines: string[] = [
|
|
445
|
+
"---",
|
|
446
|
+
`title: "Pseudo-Parameters"`,
|
|
447
|
+
`description: "Pseudo-parameters available in the ${config.displayName} lexicon"`,
|
|
448
|
+
"---",
|
|
449
|
+
"",
|
|
450
|
+
`The ${config.displayName} lexicon provides **${entries.length}** pseudo-parameters — predefined values available in every stack without explicit declaration.`,
|
|
451
|
+
"",
|
|
452
|
+
"| Name | Value |",
|
|
453
|
+
"|------|-------|",
|
|
454
|
+
];
|
|
455
|
+
|
|
456
|
+
for (const [name, value] of entries) {
|
|
457
|
+
lines.push(`| \`${name}\` | \`${value}\` |`);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
lines.push("");
|
|
461
|
+
return lines.join("\n");
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function generateRules(config: DocsConfig, rules: RuleMeta[]): string {
|
|
465
|
+
const lintRules = rules.filter((r) => r.type === "lint");
|
|
466
|
+
const postSynthRules = rules.filter((r) => r.type === "post-synth");
|
|
467
|
+
|
|
468
|
+
const lines: string[] = [
|
|
469
|
+
"---",
|
|
470
|
+
`title: "Lint Rules"`,
|
|
471
|
+
`description: "Lint rules and post-synth checks provided by the ${config.displayName} lexicon"`,
|
|
472
|
+
"---",
|
|
473
|
+
"",
|
|
474
|
+
`The ${config.displayName} lexicon provides **${rules.length}** rules: ${lintRules.length} lint rules and ${postSynthRules.length} post-synth checks.`,
|
|
475
|
+
"",
|
|
476
|
+
];
|
|
477
|
+
|
|
478
|
+
if (lintRules.length > 0) {
|
|
479
|
+
lines.push(
|
|
480
|
+
"## Lint Rules",
|
|
481
|
+
"",
|
|
482
|
+
"| ID | Severity | Category | Description |",
|
|
483
|
+
"|----|----------|----------|-------------|",
|
|
484
|
+
);
|
|
485
|
+
for (const rule of lintRules.sort((a, b) => a.id.localeCompare(b.id))) {
|
|
486
|
+
lines.push(
|
|
487
|
+
`| \`${rule.id}\` | ${rule.severity} | ${rule.category} | ${rule.description} |`,
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
lines.push("");
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
if (postSynthRules.length > 0) {
|
|
494
|
+
lines.push(
|
|
495
|
+
"## Post-Synth Checks",
|
|
496
|
+
"",
|
|
497
|
+
"Post-synth checks validate the serialized output after the build pipeline completes.",
|
|
498
|
+
"",
|
|
499
|
+
"| ID | Description |",
|
|
500
|
+
"|----|-------------|",
|
|
501
|
+
);
|
|
502
|
+
for (const rule of postSynthRules.sort((a, b) =>
|
|
503
|
+
a.id.localeCompare(b.id),
|
|
504
|
+
)) {
|
|
505
|
+
lines.push(`| \`${rule.id}\` | ${rule.description} |`);
|
|
506
|
+
}
|
|
507
|
+
lines.push("");
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
return lines.join("\n");
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function generateSerialization(config: DocsConfig): string {
|
|
514
|
+
const lines: string[] = [
|
|
515
|
+
"---",
|
|
516
|
+
`title: "Serialization"`,
|
|
517
|
+
`description: "Output format for the ${config.displayName} lexicon"`,
|
|
518
|
+
"---",
|
|
519
|
+
"",
|
|
520
|
+
];
|
|
521
|
+
|
|
522
|
+
if (config.outputFormat) {
|
|
523
|
+
lines.push(config.outputFormat);
|
|
524
|
+
} else {
|
|
525
|
+
lines.push(
|
|
526
|
+
`The ${config.displayName} lexicon serializes resources into its native output format during the build step.`,
|
|
527
|
+
"",
|
|
528
|
+
"See the [Serialization](/serialization/output-formats) guide for general information about output formats in chant.",
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
lines.push("");
|
|
533
|
+
return lines.join("\n");
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// ── Rule scanning ──────────────────────────────────────────────────
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Scan lint rule and post-synth check source files to extract metadata.
|
|
540
|
+
* Uses regex to find id, severity, category, and description from source.
|
|
541
|
+
*/
|
|
542
|
+
function scanRules(srcDir: string): RuleMeta[] {
|
|
543
|
+
const rules: RuleMeta[] = [];
|
|
544
|
+
|
|
545
|
+
// Scan lint rules
|
|
546
|
+
scanDir(join(srcDir, "lint", "rules"), "lint", rules);
|
|
547
|
+
|
|
548
|
+
// Scan post-synth checks
|
|
549
|
+
scanDir(join(srcDir, "lint", "post-synth"), "post-synth", rules);
|
|
550
|
+
|
|
551
|
+
return rules;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
function scanDir(dir: string, type: "lint" | "post-synth", out: RuleMeta[]): void {
|
|
555
|
+
let entries: string[];
|
|
556
|
+
try {
|
|
557
|
+
entries = readdirSync(dir);
|
|
558
|
+
} catch {
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
for (const entry of entries) {
|
|
563
|
+
if (!entry.endsWith(".ts")) continue;
|
|
564
|
+
if (entry.endsWith(".test.ts")) continue;
|
|
565
|
+
if (entry === "index.ts") continue;
|
|
566
|
+
// Skip utility files (no rule definitions)
|
|
567
|
+
if (entry === "cf-refs.ts") continue;
|
|
568
|
+
|
|
569
|
+
let content: string;
|
|
570
|
+
try {
|
|
571
|
+
content = readFileSync(join(dir, entry), "utf-8");
|
|
572
|
+
} catch {
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
if (type === "lint") {
|
|
577
|
+
// Extract from LintRule objects: id, severity, category
|
|
578
|
+
const idMatch = content.match(/id:\s*"([^"]+)"/);
|
|
579
|
+
const severityMatch = content.match(/severity:\s*"([^"]+)"/);
|
|
580
|
+
const categoryMatch = content.match(/category:\s*"([^"]+)"/);
|
|
581
|
+
|
|
582
|
+
if (idMatch) {
|
|
583
|
+
// Try to get description from JSDoc comment
|
|
584
|
+
const descMatch = content.match(
|
|
585
|
+
new RegExp(`\\*\\s*${idMatch[1]}:\\s*(.+?)\\n`),
|
|
586
|
+
);
|
|
587
|
+
|
|
588
|
+
out.push({
|
|
589
|
+
id: idMatch[1],
|
|
590
|
+
severity: severityMatch?.[1] ?? "warning",
|
|
591
|
+
category: categoryMatch?.[1] ?? "general",
|
|
592
|
+
description:
|
|
593
|
+
descMatch?.[1]?.trim() ??
|
|
594
|
+
extractDescriptionFromComment(content, idMatch[1]),
|
|
595
|
+
type: "lint",
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
} else {
|
|
599
|
+
// Extract from PostSynthCheck objects: id, description
|
|
600
|
+
const idMatch = content.match(/id:\s*"([^"]+)"/);
|
|
601
|
+
const descMatch = content.match(/description:\s*"([^"]+)"/);
|
|
602
|
+
|
|
603
|
+
if (idMatch) {
|
|
604
|
+
out.push({
|
|
605
|
+
id: idMatch[1],
|
|
606
|
+
severity: "error",
|
|
607
|
+
category: "post-synth",
|
|
608
|
+
description: descMatch?.[1] ?? idMatch[1],
|
|
609
|
+
type: "post-synth",
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
function extractDescriptionFromComment(
|
|
617
|
+
content: string,
|
|
618
|
+
ruleId: string,
|
|
619
|
+
): string {
|
|
620
|
+
// Try to extract from the first line after the rule ID in JSDoc
|
|
621
|
+
const pattern = new RegExp(
|
|
622
|
+
`${ruleId}[:\\s]+([^\\n]+?)\\n\\s*\\*\\s*\\n\\s*\\*\\s*(.+?)\\n`,
|
|
623
|
+
);
|
|
624
|
+
const match = content.match(pattern);
|
|
625
|
+
if (match) return match[1].trim();
|
|
626
|
+
|
|
627
|
+
// Fallback: use text after "ruleId:" in JSDoc
|
|
628
|
+
const simpleMatch = content.match(
|
|
629
|
+
new RegExp(`\\*\\s*${ruleId}:\\s*(.+?)(?:\\n|\\*)`),
|
|
630
|
+
);
|
|
631
|
+
if (simpleMatch) return simpleMatch[1].trim();
|
|
632
|
+
|
|
633
|
+
return ruleId;
|
|
634
|
+
}
|