@untangle-code/context-artifacts 0.0.0-stage → 0.1.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/LICENSE +661 -0
- package/NOTICE +90 -0
- package/README.md +247 -2
- package/THIRD_PARTY_LICENSES.md +24 -0
- package/dist/adapters/asyncapi.d.ts +20 -0
- package/dist/adapters/asyncapi.d.ts.map +1 -0
- package/dist/adapters/asyncapi.js +95 -0
- package/dist/adapters/asyncapi.js.map +1 -0
- package/dist/adapters/docker.d.ts +43 -0
- package/dist/adapters/docker.d.ts.map +1 -0
- package/dist/adapters/docker.js +97 -0
- package/dist/adapters/docker.js.map +1 -0
- package/dist/adapters/kubernetes.d.ts +22 -0
- package/dist/adapters/kubernetes.d.ts.map +1 -0
- package/dist/adapters/kubernetes.js +56 -0
- package/dist/adapters/kubernetes.js.map +1 -0
- package/dist/adapters/markdown.d.ts +35 -0
- package/dist/adapters/markdown.d.ts.map +1 -0
- package/dist/adapters/markdown.js +36 -0
- package/dist/adapters/markdown.js.map +1 -0
- package/dist/adapters/openapi.d.ts +21 -0
- package/dist/adapters/openapi.d.ts.map +1 -0
- package/dist/adapters/openapi.js +101 -0
- package/dist/adapters/openapi.js.map +1 -0
- package/dist/adapters/protobuf.d.ts +34 -0
- package/dist/adapters/protobuf.d.ts.map +1 -0
- package/dist/adapters/protobuf.js +221 -0
- package/dist/adapters/protobuf.js.map +1 -0
- package/dist/adapters/shared.d.ts +65 -0
- package/dist/adapters/shared.d.ts.map +1 -0
- package/dist/adapters/shared.js +95 -0
- package/dist/adapters/shared.js.map +1 -0
- package/dist/adapters/sql.d.ts +104 -0
- package/dist/adapters/sql.d.ts.map +1 -0
- package/dist/adapters/sql.js +427 -0
- package/dist/adapters/sql.js.map +1 -0
- package/dist/adapters/terraform.d.ts +40 -0
- package/dist/adapters/terraform.d.ts.map +1 -0
- package/dist/adapters/terraform.js +186 -0
- package/dist/adapters/terraform.js.map +1 -0
- package/dist/adapters/text.d.ts +24 -0
- package/dist/adapters/text.d.ts.map +1 -0
- package/dist/adapters/text.js +31 -0
- package/dist/adapters/text.js.map +1 -0
- package/dist/config-validation.d.ts +18 -0
- package/dist/config-validation.d.ts.map +1 -0
- package/dist/config-validation.js +30 -0
- package/dist/config-validation.js.map +1 -0
- package/dist/coverage.d.ts +114 -0
- package/dist/coverage.d.ts.map +1 -0
- package/dist/coverage.js +0 -0
- package/dist/coverage.js.map +1 -0
- package/dist/ids.d.ts +12 -0
- package/dist/ids.d.ts.map +1 -0
- package/dist/ids.js +42 -0
- package/dist/ids.js.map +1 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/registry.d.ts +51 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +86 -0
- package/dist/registry.js.map +1 -0
- package/dist/staleness.d.ts +44 -0
- package/dist/staleness.d.ts.map +1 -0
- package/dist/staleness.js +35 -0
- package/dist/staleness.js.map +1 -0
- package/dist/text/delimiter-balance.d.ts +95 -0
- package/dist/text/delimiter-balance.d.ts.map +1 -0
- package/dist/text/delimiter-balance.js +209 -0
- package/dist/text/delimiter-balance.js.map +1 -0
- package/dist/text/line-index.d.ts +61 -0
- package/dist/text/line-index.d.ts.map +1 -0
- package/dist/text/line-index.js +75 -0
- package/dist/text/line-index.js.map +1 -0
- package/dist/text/yaml-lite.d.ts +73 -0
- package/dist/text/yaml-lite.d.ts.map +1 -0
- package/dist/text/yaml-lite.js +486 -0
- package/dist/text/yaml-lite.js.map +1 -0
- package/package.json +61 -3
- package/src/adapters/__golden__/adr-0001-sections.json +68 -0
- package/src/adapters/__golden__/app-compose-services.json +24 -0
- package/src/adapters/__golden__/app-image-stages.json +24 -0
- package/src/adapters/__golden__/infra-main-sections.json +46 -0
- package/src/adapters/__golden__/orders-events-operations.json +24 -0
- package/src/adapters/__golden__/orders-proto-sections.json +57 -0
- package/src/adapters/__golden__/orders-schema-statements.json +68 -0
- package/src/adapters/__golden__/users-api-operations.json +46 -0
- package/src/adapters/__golden__/web-manifests-resources.json +24 -0
- package/src/adapters/asyncapi.ts +147 -0
- package/src/adapters/docker.ts +170 -0
- package/src/adapters/kubernetes.ts +103 -0
- package/src/adapters/markdown.ts +88 -0
- package/src/adapters/openapi.ts +156 -0
- package/src/adapters/protobuf.ts +286 -0
- package/src/adapters/shared.ts +151 -0
- package/src/adapters/sql.ts +555 -0
- package/src/adapters/terraform.ts +261 -0
- package/src/adapters/text.ts +72 -0
- package/src/config-validation.ts +41 -0
- package/src/coverage.ts +336 -0
- package/src/ids.ts +57 -0
- package/src/index.ts +105 -0
- package/src/registry.ts +155 -0
- package/src/staleness.ts +69 -0
- package/src/text/delimiter-balance.ts +295 -0
- package/src/text/line-index.ts +108 -0
- package/src/text/yaml-lite.ts +565 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { createArtifactAdapterRegistry } from "./registry.js";
|
|
2
|
+
export { createMarkdownAdapter } from "./adapters/markdown.js";
|
|
3
|
+
export { createSqlAdapter, DEFAULT_SQL_DIALECT } from "./adapters/sql.js";
|
|
4
|
+
export { createOpenApiAdapter } from "./adapters/openapi.js";
|
|
5
|
+
export { createAsyncApiAdapter } from "./adapters/asyncapi.js";
|
|
6
|
+
export { createProtobufAdapter } from "./adapters/protobuf.js";
|
|
7
|
+
export { createTerraformAdapter } from "./adapters/terraform.js";
|
|
8
|
+
export { createKubernetesAdapter } from "./adapters/kubernetes.js";
|
|
9
|
+
export { createDockerAdapter } from "./adapters/docker.js";
|
|
10
|
+
export { createTextFallbackAdapter, TEXT_WINDOW_LINES } from "./adapters/text.js";
|
|
11
|
+
export { validateArtifactConfigs } from "./config-validation.js";
|
|
12
|
+
export { computeArtifactConfigHash, computeArtifactContentHash, computeArtifactStalenessSnapshot, isArtifactStale, } from "./staleness.js";
|
|
13
|
+
export { buildArtifactSkipLedger, defaultSkipLedgerReporter } from "./coverage.js";
|
|
14
|
+
export { buildArtifactChunkId } from "./ids.js";
|
|
15
|
+
export { buildLineIndex, rangeForLines, sliceBytes, sliceLines, splitLines, } from "./text/line-index.js";
|
|
16
|
+
export { describeDelimiterImbalances, findDelimiterImbalances } from "./text/delimiter-balance.js";
|
|
17
|
+
export { YamlParseError, mapGet, parseYamlNode, scalarString, splitYamlDocuments, } from "./text/yaml-lite.js";
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,6BAA6B,EAAE,MAAM,eAAe,CAAC;AAG9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAE,yBAAyB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAElF,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAGjE,OAAO,EACL,yBAAyB,EACzB,0BAA0B,EAC1B,gCAAgC,EAChC,eAAe,GAChB,MAAM,gBAAgB,CAAC;AASxB,OAAO,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAEnF,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAOhD,OAAO,EACL,cAAc,EACd,aAAa,EACb,UAAU,EACV,UAAU,EACV,UAAU,GACX,MAAM,sBAAsB,CAAC;AAa9B,OAAO,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAUnG,OAAO,EACL,cAAc,EACd,MAAM,EACN,aAAa,EACb,YAAY,EACZ,kBAAkB,GACnB,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ArtifactAdapterRegistry` (architecture.md §20) — a composite
|
|
3
|
+
* `ArtifactAdapter` that dispatches to the right concrete format adapter
|
|
4
|
+
* and NEVER fails to produce a result: the generic text-fallback adapter
|
|
5
|
+
* is always registered last as a catch-all, so `read()`/`chunk()` always
|
|
6
|
+
* succeed for every file (spec.md §19.2's "sicherer Text-Fallback";
|
|
7
|
+
* rule 4 / BUILD_PLAN §12 E4 — nothing is silently unindexable).
|
|
8
|
+
*
|
|
9
|
+
* Dispatch order (auto-detection priority, see each adapter's own
|
|
10
|
+
* `supports()` for its exact rule):
|
|
11
|
+
*
|
|
12
|
+
* 1. OpenAPI / AsyncAPI — filename-hint + yaml/json extension
|
|
13
|
+
* 2. Docker / Compose — `Dockerfile*` / `(docker-)compose.y*ml` filename
|
|
14
|
+
* 3. Kubernetes — any other `.yaml`/`.yml`
|
|
15
|
+
* 4. Markdown, SQL, Protobuf, Terraform — unambiguous extensions
|
|
16
|
+
* 5. Text fallback — catch-all
|
|
17
|
+
*
|
|
18
|
+
* `chunk()`/`links()` reuse the SAME per-adapter `supports()` rule, called
|
|
19
|
+
* with `(document.type, document.path)` instead of the config's declared
|
|
20
|
+
* type — every non-"text" `ArtifactDocument.type` is itself one adapter's
|
|
21
|
+
* own literal (`"sql"`, `"openapi"`, …), so this always resolves
|
|
22
|
+
* correctly without needing a second identity mechanism; the Docker
|
|
23
|
+
* adapter's `supports()` additionally recognizes `type === "text"` for
|
|
24
|
+
* exactly this reason (its documents carry type `"text"`, see `docker.ts`).
|
|
25
|
+
*/
|
|
26
|
+
import type { ArtifactAdapter } from "@untangle-code/domain";
|
|
27
|
+
import type { SkipLedgerReporter } from "./adapters/shared.js";
|
|
28
|
+
export interface ArtifactAdapterRegistry extends ArtifactAdapter {
|
|
29
|
+
/** Registers an additional adapter with LOWER priority than every built-in one (inserted just before the text fallback). */
|
|
30
|
+
register(adapter: ArtifactAdapter): void;
|
|
31
|
+
listAdapters(): readonly ArtifactAdapter[];
|
|
32
|
+
}
|
|
33
|
+
export interface ArtifactAdapterRegistryOptions {
|
|
34
|
+
/**
|
|
35
|
+
* BUILD_PLAN §12 E4: overrides how every BUILT-IN adapter's `chunk()`
|
|
36
|
+
* surfaces a real skip-ledger finding (default: one stderr warning line
|
|
37
|
+
* per finding — see `coverage.ts`'s `defaultSkipLedgerReporter`). Wire in
|
|
38
|
+
* a real structured logger here once, instead of passing the same
|
|
39
|
+
* `onSkipLedgerGap` to every individual `create*Adapter()` call. Does
|
|
40
|
+
* NOT apply to `extra` adapters — those are already fully constructed
|
|
41
|
+
* `ArtifactAdapter`s by the time they reach this factory.
|
|
42
|
+
*/
|
|
43
|
+
onSkipLedgerGap?: SkipLedgerReporter;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Builds a registry with every built-in format adapter registered
|
|
47
|
+
* (priority order per this module's doc comment), plus any `extra`
|
|
48
|
+
* adapters appended just before the text fallback.
|
|
49
|
+
*/
|
|
50
|
+
export declare function createArtifactAdapterRegistry(extra?: ArtifactAdapter[], options?: ArtifactAdapterRegistryOptions): ArtifactAdapterRegistry;
|
|
51
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,EACV,eAAe,EAMhB,MAAM,uBAAuB,CAAC;AAS/B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAK/D,MAAM,WAAW,uBAAwB,SAAQ,eAAe;IAC9D,4HAA4H;IAC5H,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CAAC;IACzC,YAAY,IAAI,SAAS,eAAe,EAAE,CAAC;CAC5C;AAoED,MAAM,WAAW,8BAA8B;IAC7C;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,kBAAkB,CAAC;CACtC;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,GAAE,eAAe,EAAO,EAC7B,OAAO,GAAE,8BAAmC,GAC3C,uBAAuB,CAezB"}
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { jobCancelledError } from "@untangle-code/observability";
|
|
2
|
+
import { createAsyncApiAdapter } from "./adapters/asyncapi.js";
|
|
3
|
+
import { createDockerAdapter } from "./adapters/docker.js";
|
|
4
|
+
import { createKubernetesAdapter } from "./adapters/kubernetes.js";
|
|
5
|
+
import { createMarkdownAdapter } from "./adapters/markdown.js";
|
|
6
|
+
import { createOpenApiAdapter } from "./adapters/openapi.js";
|
|
7
|
+
import { createProtobufAdapter } from "./adapters/protobuf.js";
|
|
8
|
+
import { createSqlAdapter } from "./adapters/sql.js";
|
|
9
|
+
import { createTerraformAdapter } from "./adapters/terraform.js";
|
|
10
|
+
import { createTextFallbackAdapter } from "./adapters/text.js";
|
|
11
|
+
class DefaultArtifactAdapterRegistry {
|
|
12
|
+
textFallback;
|
|
13
|
+
adapters;
|
|
14
|
+
constructor(builtins, textFallback) {
|
|
15
|
+
this.textFallback = textFallback;
|
|
16
|
+
this.adapters = [...builtins, textFallback];
|
|
17
|
+
}
|
|
18
|
+
register(adapter) {
|
|
19
|
+
// Keep the text fallback last no matter when custom adapters are added.
|
|
20
|
+
const withoutFallback = this.adapters.filter((existing) => existing !== this.textFallback);
|
|
21
|
+
this.adapters = [...withoutFallback, adapter, this.textFallback];
|
|
22
|
+
}
|
|
23
|
+
listAdapters() {
|
|
24
|
+
return [...this.adapters];
|
|
25
|
+
}
|
|
26
|
+
supports(type, path) {
|
|
27
|
+
return this.adapters.some((adapter) => adapter.supports(type, path));
|
|
28
|
+
}
|
|
29
|
+
resolve(type, path) {
|
|
30
|
+
return this.adapters.find((adapter) => adapter.supports(type, path)) ?? this.textFallback;
|
|
31
|
+
}
|
|
32
|
+
async read(input, options) {
|
|
33
|
+
const declaredType = input.config.type ?? "auto";
|
|
34
|
+
const groups = new Map();
|
|
35
|
+
for (const file of input.files) {
|
|
36
|
+
if (options?.signal?.aborted) {
|
|
37
|
+
throw jobCancelledError(`context artifact "${input.config.name}" read was aborted`, {
|
|
38
|
+
operation: "context_artifact_read",
|
|
39
|
+
context: { artifactName: input.config.name },
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
const adapter = this.resolve(declaredType, file.path);
|
|
43
|
+
const existing = groups.get(adapter);
|
|
44
|
+
if (existing) {
|
|
45
|
+
existing.push(file);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
groups.set(adapter, [file]);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const documents = [];
|
|
52
|
+
for (const [adapter, files] of groups) {
|
|
53
|
+
const group = await adapter.read({ config: input.config, files }, options);
|
|
54
|
+
documents.push(...group);
|
|
55
|
+
}
|
|
56
|
+
return documents;
|
|
57
|
+
}
|
|
58
|
+
chunk(document) {
|
|
59
|
+
return this.resolve(document.type, document.path).chunk(document);
|
|
60
|
+
}
|
|
61
|
+
links(document) {
|
|
62
|
+
const adapter = this.resolve(document.type, document.path);
|
|
63
|
+
return adapter.links?.(document) ?? [];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Builds a registry with every built-in format adapter registered
|
|
68
|
+
* (priority order per this module's doc comment), plus any `extra`
|
|
69
|
+
* adapters appended just before the text fallback.
|
|
70
|
+
*/
|
|
71
|
+
export function createArtifactAdapterRegistry(extra = [], options = {}) {
|
|
72
|
+
const adapterOptions = options.onSkipLedgerGap === undefined ? {} : { onSkipLedgerGap: options.onSkipLedgerGap };
|
|
73
|
+
const builtins = [
|
|
74
|
+
createOpenApiAdapter(adapterOptions),
|
|
75
|
+
createAsyncApiAdapter(adapterOptions),
|
|
76
|
+
createDockerAdapter(adapterOptions),
|
|
77
|
+
createKubernetesAdapter(adapterOptions),
|
|
78
|
+
createMarkdownAdapter(adapterOptions),
|
|
79
|
+
createSqlAdapter(adapterOptions),
|
|
80
|
+
createProtobufAdapter(adapterOptions),
|
|
81
|
+
createTerraformAdapter(adapterOptions),
|
|
82
|
+
...extra,
|
|
83
|
+
];
|
|
84
|
+
return new DefaultArtifactAdapterRegistry(builtins, createTextFallbackAdapter(adapterOptions));
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Staleness detection (spec.md §19.2: "Artefaktkonfiguration und
|
|
3
|
+
* Inhaltshash MÜSSEN Staleness bestimmen.").
|
|
4
|
+
*
|
|
5
|
+
* A context artifact goes stale when EITHER its configuration changes
|
|
6
|
+
* (e.g. `include`/`exclude` edited, `description` reworded, `path`
|
|
7
|
+
* repointed) OR its underlying file content changes (a file was edited,
|
|
8
|
+
* added, or removed), independently of each other — so both are hashed
|
|
9
|
+
* separately and compared separately; collapsing them into one combined
|
|
10
|
+
* hash would make "what changed" undiagnosable from the stored snapshot
|
|
11
|
+
* alone.
|
|
12
|
+
*/
|
|
13
|
+
import type { ArtifactDocument, ContextArtifactConfig } from "@untangle-code/domain";
|
|
14
|
+
/** The two independent inputs to staleness (spec.md §19.2), snapshotted together. */
|
|
15
|
+
export interface ArtifactStalenessSnapshot {
|
|
16
|
+
/** SHA-256 of the canonical JSON of the artifact's `ContextArtifactConfig`. */
|
|
17
|
+
configHash: string;
|
|
18
|
+
/**
|
|
19
|
+
* SHA-256 combining every current document's path and content hash
|
|
20
|
+
* (spec.md §19.2's "Inhaltshash"). Sorted by path first so the result is
|
|
21
|
+
* independent of file-discovery order.
|
|
22
|
+
*/
|
|
23
|
+
contentHash: string;
|
|
24
|
+
}
|
|
25
|
+
/** SHA-256 of an artifact's canonical configuration (spec.md §19.2). */
|
|
26
|
+
export declare function computeArtifactConfigHash(config: ContextArtifactConfig): string;
|
|
27
|
+
/**
|
|
28
|
+
* Combines the per-document `contentHash`es (already SHA-256 of each
|
|
29
|
+
* document's raw content, per `ArtifactDocument.contentHash`) into one
|
|
30
|
+
* artifact-level content hash. A directory-backed artifact is stale when
|
|
31
|
+
* any file's content changes, a file is added, or a file is removed — all
|
|
32
|
+
* three change this combined hash.
|
|
33
|
+
*/
|
|
34
|
+
export declare function computeArtifactContentHash(documents: readonly ArtifactDocument[]): string;
|
|
35
|
+
/** Snapshots both staleness inputs for one artifact's current config + documents. */
|
|
36
|
+
export declare function computeArtifactStalenessSnapshot(config: ContextArtifactConfig, documents: readonly ArtifactDocument[]): ArtifactStalenessSnapshot;
|
|
37
|
+
/**
|
|
38
|
+
* True when `current` differs from the last-indexed `previous` snapshot in
|
|
39
|
+
* either the config hash or the content hash (spec.md §19.2) — a pure
|
|
40
|
+
* comparison; persisting/loading the previous snapshot is a metadata-store
|
|
41
|
+
* concern outside this package.
|
|
42
|
+
*/
|
|
43
|
+
export declare function isArtifactStale(previous: ArtifactStalenessSnapshot, current: ArtifactStalenessSnapshot): boolean;
|
|
44
|
+
//# sourceMappingURL=staleness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staleness.d.ts","sourceRoot":"","sources":["../src/staleness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAGrF,qFAAqF;AACrF,MAAM,WAAW,yBAAyB;IACxC,+EAA+E;IAC/E,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wEAAwE;AACxE,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,CAE/E;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,SAAS,gBAAgB,EAAE,GAAG,MAAM,CAKzF;AAED,qFAAqF;AACrF,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,qBAAqB,EAC7B,SAAS,EAAE,SAAS,gBAAgB,EAAE,GACrC,yBAAyB,CAK3B;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,yBAAyB,EACnC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAET"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { canonicalJson, sha256Hex } from "@untangle-code/domain";
|
|
2
|
+
/** SHA-256 of an artifact's canonical configuration (spec.md §19.2). */
|
|
3
|
+
export function computeArtifactConfigHash(config) {
|
|
4
|
+
return sha256Hex(canonicalJson(config));
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Combines the per-document `contentHash`es (already SHA-256 of each
|
|
8
|
+
* document's raw content, per `ArtifactDocument.contentHash`) into one
|
|
9
|
+
* artifact-level content hash. A directory-backed artifact is stale when
|
|
10
|
+
* any file's content changes, a file is added, or a file is removed — all
|
|
11
|
+
* three change this combined hash.
|
|
12
|
+
*/
|
|
13
|
+
export function computeArtifactContentHash(documents) {
|
|
14
|
+
const sorted = [...documents]
|
|
15
|
+
.map((document) => ({ path: document.path, contentHash: document.contentHash }))
|
|
16
|
+
.sort((a, b) => a.path.localeCompare(b.path));
|
|
17
|
+
return sha256Hex(canonicalJson(sorted));
|
|
18
|
+
}
|
|
19
|
+
/** Snapshots both staleness inputs for one artifact's current config + documents. */
|
|
20
|
+
export function computeArtifactStalenessSnapshot(config, documents) {
|
|
21
|
+
return {
|
|
22
|
+
configHash: computeArtifactConfigHash(config),
|
|
23
|
+
contentHash: computeArtifactContentHash(documents),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* True when `current` differs from the last-indexed `previous` snapshot in
|
|
28
|
+
* either the config hash or the content hash (spec.md §19.2) — a pure
|
|
29
|
+
* comparison; persisting/loading the previous snapshot is a metadata-store
|
|
30
|
+
* concern outside this package.
|
|
31
|
+
*/
|
|
32
|
+
export function isArtifactStale(previous, current) {
|
|
33
|
+
return previous.configHash !== current.configHash || previous.contentHash !== current.contentHash;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=staleness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staleness.js","sourceRoot":"","sources":["../src/staleness.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAcjE,wEAAwE;AACxE,MAAM,UAAU,yBAAyB,CAAC,MAA6B;IACrE,OAAO,SAAS,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,0BAA0B,CAAC,SAAsC;IAC/E,MAAM,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;SAC1B,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;SAC/E,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAChD,OAAO,SAAS,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,gCAAgC,CAC9C,MAA6B,EAC7B,SAAsC;IAEtC,OAAO;QACL,UAAU,EAAE,yBAAyB,CAAC,MAAM,CAAC;QAC7C,WAAW,EAAE,0BAA0B,CAAC,SAAS,CAAC;KACnD,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAC7B,QAAmC,EACnC,OAAkC;IAElC,OAAO,QAAQ,CAAC,UAAU,KAAK,OAAO,CAAC,UAAU,IAAI,QAAQ,CAAC,WAAW,KAAK,OAAO,CAAC,WAAW,CAAC;AACpG,CAAC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plausibilitätsprüfung von Fragmentgrenzen (WP-118, BUILD_PLAN §12 E4).
|
|
3
|
+
*
|
|
4
|
+
* `coverage.ts` beantwortet die Frage „**fehlt** etwas?" — es rechnet
|
|
5
|
+
* Byte-Abdeckung und meldet jeden Bereich, der in keinem Chunk landet.
|
|
6
|
+
* Diese Frage ist blind gegenüber dem zweiten Fehlerbild: es fehlt nichts,
|
|
7
|
+
* aber es ist **falsch geschnitten**. Der Auslöser war die SQL-Zerlegung
|
|
8
|
+
* (`adapters/sql.ts`), die `INSERT INTO t VALUES ('it\'s a test; nested
|
|
9
|
+
* clause', 2);` in zwei syntaktisch kaputte Fragmente zerriss — bei
|
|
10
|
+
* lückenloser Byte-Abdeckung, ohne leere oder überlappende Ranges, also bei
|
|
11
|
+
* **null** Ledger-Einträgen. Der Verlust ist real (kein Fragment ist ein
|
|
12
|
+
* gültiges Statement, die Einbettung beider ist Müll), nur eben unsichtbar.
|
|
13
|
+
*
|
|
14
|
+
* Dieses Modul liefert das fehlende Signal, format-agnostisch und ohne
|
|
15
|
+
* Grammatik: ein korrekt geschnittenes Fragment einer klammer- und
|
|
16
|
+
* zeichenketten-strukturierten Sprache ist in sich **ausbalanciert**. Bleibt
|
|
17
|
+
* eine Zeichenkette, ein Blockkommentar, ein Heredoc oder eine Klammer am
|
|
18
|
+
* Fragmentende offen, dann verlief die Schnittkante mitten durch ein
|
|
19
|
+
* Konstrukt — unabhängig davon, welcher Adapter geschnitten hat und warum.
|
|
20
|
+
*
|
|
21
|
+
* Bewusste Asymmetrie zum jeweiligen Zerleger: dieser Prüfer darf
|
|
22
|
+
* **misstrauischer** sein als der Zerleger. Ein Fehlalarm kostet eine
|
|
23
|
+
* Warnzeile, ein verschwiegener Fehlschnitt kostet einen unbrauchbaren
|
|
24
|
+
* Chunk (E4). Deshalb kennt er z. B. Dollar-Quoting auch dort, wo ein
|
|
25
|
+
* Dialekt es nicht erwarten ließe.
|
|
26
|
+
*
|
|
27
|
+
* Was er NICHT ist: ein Parser. Er kennt keine Schlüsselwörter, keine
|
|
28
|
+
* Ausdrücke, keine Typen. Ein Fragment, das balanciert und trotzdem
|
|
29
|
+
* bedeutungslos ist (`FROM orders WHERE`), passiert ihn unbeanstandet. Das
|
|
30
|
+
* ist die dokumentierte Grenze — er schließt die Lücke „mitten durch ein
|
|
31
|
+
* Konstrukt geschnitten", nicht „semantisch unvollständig".
|
|
32
|
+
*/
|
|
33
|
+
/** Eine Zeichenketten-/Bezeichner-Anführungskonvention (`'…'`, `"…"`, `` `…` ``). */
|
|
34
|
+
export interface QuoteRule {
|
|
35
|
+
/** Öffnende Zeichenfolge, meist ein einzelnes Zeichen. */
|
|
36
|
+
readonly open: string;
|
|
37
|
+
/** Schließende Zeichenfolge; bei symmetrischen Anführungszeichen gleich `open`. */
|
|
38
|
+
readonly close: string;
|
|
39
|
+
/** Ob ein `\` innerhalb des Literals das folgende Zeichen maskiert (dialektabhängig, siehe `adapters/sql.ts`). */
|
|
40
|
+
readonly backslashEscapes: boolean;
|
|
41
|
+
/** Ob ein verdoppeltes Schlusszeichen (`''`) im Literal ein maskiertes Anführungszeichen ist. */
|
|
42
|
+
readonly doubledEscapes: boolean;
|
|
43
|
+
/** Ob das Literal einen Zeilenumbruch enthalten darf. Ist es das nicht, ist ein Zeilenende im Literal selbst schon ein Befund. */
|
|
44
|
+
readonly spansLines: boolean;
|
|
45
|
+
}
|
|
46
|
+
/** Ein Klammerpaar, dessen Verschachtelung aufgehen muss. */
|
|
47
|
+
export interface BracketRule {
|
|
48
|
+
readonly open: string;
|
|
49
|
+
readonly close: string;
|
|
50
|
+
}
|
|
51
|
+
/** Ein Blockkommentar-Paar (`/*` … `*\/`). */
|
|
52
|
+
export interface BlockCommentRule {
|
|
53
|
+
readonly open: string;
|
|
54
|
+
readonly close: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Heredoc-Konvention. Bisher nur `"hcl"`: `<<TAG` bzw. `<<-TAG`, beendet
|
|
58
|
+
* durch eine Zeile, deren getrimmter Inhalt genau `TAG` ist. Der Inhalt
|
|
59
|
+
* eines Heredocs ist Rohtext — Klammern und Anführungszeichen darin zählen
|
|
60
|
+
* nicht, sonst meldet jedes eingebettete Shell-Skript einen Fehlalarm.
|
|
61
|
+
*/
|
|
62
|
+
export type HeredocStyle = "hcl";
|
|
63
|
+
export interface DelimiterScanOptions {
|
|
64
|
+
readonly quotes: readonly QuoteRule[];
|
|
65
|
+
readonly brackets: readonly BracketRule[];
|
|
66
|
+
/** Zeilenkommentar-Präfixe (`"--"`, `"//"`, `"#"`), in Prüfreihenfolge. */
|
|
67
|
+
readonly lineComments: readonly string[];
|
|
68
|
+
readonly blockComment?: BlockCommentRule;
|
|
69
|
+
/**
|
|
70
|
+
* `$tag$ … $tag$`-Literale erkennen. Ein Öffner zählt nur, wenn davor
|
|
71
|
+
* kein Bezeichnerzeichen steht — sonst würde ein Bezeichner mit zwei
|
|
72
|
+
* `$` (`my$col$x`) fälschlich ein Literal öffnen.
|
|
73
|
+
*/
|
|
74
|
+
readonly dollarQuotedStrings?: boolean;
|
|
75
|
+
readonly heredocs?: HeredocStyle;
|
|
76
|
+
}
|
|
77
|
+
export type DelimiterImbalanceKind = "unterminated_string" | "unterminated_block_comment" | "unterminated_heredoc" | "unclosed_bracket" | "unmatched_closing_bracket";
|
|
78
|
+
export interface DelimiterImbalance {
|
|
79
|
+
readonly kind: DelimiterImbalanceKind;
|
|
80
|
+
/** Das beteiligte Trennzeichen, wörtlich (`"'"`, `"("`, `"<<EOF"`). */
|
|
81
|
+
readonly delimiter: string;
|
|
82
|
+
/** 0-basierter Offset in der geprüften Zeichenkette (UTF-16-Einheiten), an dem das Konstrukt geöffnet wurde. */
|
|
83
|
+
readonly offset: number;
|
|
84
|
+
/** 1-basierte Zeile INNERHALB des geprüften Fragments (nicht des Dokuments). */
|
|
85
|
+
readonly line: number;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Findet jede Stelle, an der `text` mitten durch ein Konstrukt geschnitten
|
|
89
|
+
* ist. Ergebnis ist deterministisch nach Offset sortiert (numerisch, kein
|
|
90
|
+
* `localeCompare`) und auf {@link MAX_IMBALANCES} Einträge begrenzt.
|
|
91
|
+
*/
|
|
92
|
+
export declare function findDelimiterImbalances(text: string, options: DelimiterScanOptions): DelimiterImbalance[];
|
|
93
|
+
/** Einzeilige, menschenlesbare Zusammenfassung für den `contentPreview` eines Ledger-Eintrags. */
|
|
94
|
+
export declare function describeDelimiterImbalances(imbalances: readonly DelimiterImbalance[]): string;
|
|
95
|
+
//# sourceMappingURL=delimiter-balance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delimiter-balance.d.ts","sourceRoot":"","sources":["../../src/text/delimiter-balance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,qFAAqF;AACrF,MAAM,WAAW,SAAS;IACxB,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mFAAmF;IACnF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,kHAAkH;IAClH,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC,iGAAiG;IACjG,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,kIAAkI;IAClI,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC9B;AAED,6DAA6D;AAC7D,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,8CAA8C;AAC9C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,KAAK,CAAC;AAEjC,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,CAAC;IACtC,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IAC1C,2EAA2E;IAC3E,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,YAAY,CAAC,EAAE,gBAAgB,CAAC;IACzC;;;;OAIG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC;CAClC;AAED,MAAM,MAAM,sBAAsB,GAC9B,qBAAqB,GACrB,4BAA4B,GAC5B,sBAAsB,GACtB,kBAAkB,GAClB,2BAA2B,CAAC;AAEhC,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;IACtC,uEAAuE;IACvE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,gHAAgH;IAChH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAmFD;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,oBAAoB,GAC5B,kBAAkB,EAAE,CAyFtB;AAUD,kGAAkG;AAClG,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,GAAG,MAAM,CAM7F"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plausibilitätsprüfung von Fragmentgrenzen (WP-118, BUILD_PLAN §12 E4).
|
|
3
|
+
*
|
|
4
|
+
* `coverage.ts` beantwortet die Frage „**fehlt** etwas?" — es rechnet
|
|
5
|
+
* Byte-Abdeckung und meldet jeden Bereich, der in keinem Chunk landet.
|
|
6
|
+
* Diese Frage ist blind gegenüber dem zweiten Fehlerbild: es fehlt nichts,
|
|
7
|
+
* aber es ist **falsch geschnitten**. Der Auslöser war die SQL-Zerlegung
|
|
8
|
+
* (`adapters/sql.ts`), die `INSERT INTO t VALUES ('it\'s a test; nested
|
|
9
|
+
* clause', 2);` in zwei syntaktisch kaputte Fragmente zerriss — bei
|
|
10
|
+
* lückenloser Byte-Abdeckung, ohne leere oder überlappende Ranges, also bei
|
|
11
|
+
* **null** Ledger-Einträgen. Der Verlust ist real (kein Fragment ist ein
|
|
12
|
+
* gültiges Statement, die Einbettung beider ist Müll), nur eben unsichtbar.
|
|
13
|
+
*
|
|
14
|
+
* Dieses Modul liefert das fehlende Signal, format-agnostisch und ohne
|
|
15
|
+
* Grammatik: ein korrekt geschnittenes Fragment einer klammer- und
|
|
16
|
+
* zeichenketten-strukturierten Sprache ist in sich **ausbalanciert**. Bleibt
|
|
17
|
+
* eine Zeichenkette, ein Blockkommentar, ein Heredoc oder eine Klammer am
|
|
18
|
+
* Fragmentende offen, dann verlief die Schnittkante mitten durch ein
|
|
19
|
+
* Konstrukt — unabhängig davon, welcher Adapter geschnitten hat und warum.
|
|
20
|
+
*
|
|
21
|
+
* Bewusste Asymmetrie zum jeweiligen Zerleger: dieser Prüfer darf
|
|
22
|
+
* **misstrauischer** sein als der Zerleger. Ein Fehlalarm kostet eine
|
|
23
|
+
* Warnzeile, ein verschwiegener Fehlschnitt kostet einen unbrauchbaren
|
|
24
|
+
* Chunk (E4). Deshalb kennt er z. B. Dollar-Quoting auch dort, wo ein
|
|
25
|
+
* Dialekt es nicht erwarten ließe.
|
|
26
|
+
*
|
|
27
|
+
* Was er NICHT ist: ein Parser. Er kennt keine Schlüsselwörter, keine
|
|
28
|
+
* Ausdrücke, keine Typen. Ein Fragment, das balanciert und trotzdem
|
|
29
|
+
* bedeutungslos ist (`FROM orders WHERE`), passiert ihn unbeanstandet. Das
|
|
30
|
+
* ist die dokumentierte Grenze — er schließt die Lücke „mitten durch ein
|
|
31
|
+
* Konstrukt geschnitten", nicht „semantisch unvollständig".
|
|
32
|
+
*/
|
|
33
|
+
const IDENTIFIER_CHARACTER = /[A-Za-z0-9_]/;
|
|
34
|
+
const IDENTIFIER_START = /[A-Za-z_]/;
|
|
35
|
+
const HEREDOC_OPEN = /<<-?([A-Za-z_][A-Za-z0-9_]*)/y;
|
|
36
|
+
/** Höchstzahl gemeldeter Befunde je Fragment — ein durchgehend kaputtes Fragment soll den Ledger nicht fluten. */
|
|
37
|
+
const MAX_IMBALANCES = 8;
|
|
38
|
+
function lineOf(text, offset) {
|
|
39
|
+
let line = 1;
|
|
40
|
+
for (let i = 0; i < offset && i < text.length; i += 1) {
|
|
41
|
+
if (text[i] === "\n")
|
|
42
|
+
line += 1;
|
|
43
|
+
}
|
|
44
|
+
return line;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* `$tag$`-Öffner an Position `i`, oder `undefined`. Der Tag darf leer sein
|
|
48
|
+
* (`$$`); ein vorangehendes Bezeichnerzeichen verhindert die Erkennung.
|
|
49
|
+
*/
|
|
50
|
+
function matchDollarQuote(text, i) {
|
|
51
|
+
if (text[i] !== "$")
|
|
52
|
+
return undefined;
|
|
53
|
+
const before = i > 0 ? text[i - 1] : "";
|
|
54
|
+
if (before !== "" && (IDENTIFIER_CHARACTER.test(before) || before === "$"))
|
|
55
|
+
return undefined;
|
|
56
|
+
let j = i + 1;
|
|
57
|
+
if (j < text.length && IDENTIFIER_START.test(text[j])) {
|
|
58
|
+
j += 1;
|
|
59
|
+
while (j < text.length && IDENTIFIER_CHARACTER.test(text[j]))
|
|
60
|
+
j += 1;
|
|
61
|
+
}
|
|
62
|
+
if (text[j] !== "$")
|
|
63
|
+
return undefined;
|
|
64
|
+
return text.slice(i, j + 1);
|
|
65
|
+
}
|
|
66
|
+
/** Überliest ein Literal ab dem Öffner an `start`. */
|
|
67
|
+
function scanQuoted(text, start, rule) {
|
|
68
|
+
let i = start + rule.open.length;
|
|
69
|
+
while (i < text.length) {
|
|
70
|
+
if (!rule.spansLines && text[i] === "\n")
|
|
71
|
+
return { next: i, terminated: false };
|
|
72
|
+
if (rule.backslashEscapes && text[i] === "\\") {
|
|
73
|
+
i += 2;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (text.startsWith(rule.close, i)) {
|
|
77
|
+
if (rule.doubledEscapes && text.startsWith(rule.close, i + rule.close.length)) {
|
|
78
|
+
i += rule.close.length * 2;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
return { next: i + rule.close.length, terminated: true };
|
|
82
|
+
}
|
|
83
|
+
i += 1;
|
|
84
|
+
}
|
|
85
|
+
return { next: text.length, terminated: false };
|
|
86
|
+
}
|
|
87
|
+
/** Überliest ein `$tag$`-Literal ab dem Öffner an `start`. */
|
|
88
|
+
function scanDollarQuoted(text, start, tag) {
|
|
89
|
+
const close = text.indexOf(tag, start + tag.length);
|
|
90
|
+
if (close === -1)
|
|
91
|
+
return { next: text.length, terminated: false };
|
|
92
|
+
return { next: close + tag.length, terminated: true };
|
|
93
|
+
}
|
|
94
|
+
/** Überliest ein Heredoc ab dem `<<TAG`-Öffner an `start`. */
|
|
95
|
+
function scanHeredoc(text, start, opener, tag) {
|
|
96
|
+
let lineStart = text.indexOf("\n", start + opener.length);
|
|
97
|
+
if (lineStart === -1)
|
|
98
|
+
return { next: text.length, terminated: false };
|
|
99
|
+
lineStart += 1;
|
|
100
|
+
while (lineStart <= text.length) {
|
|
101
|
+
const newline = text.indexOf("\n", lineStart);
|
|
102
|
+
const lineEnd = newline === -1 ? text.length : newline;
|
|
103
|
+
if (text.slice(lineStart, lineEnd).trim() === tag)
|
|
104
|
+
return { next: lineEnd, terminated: true };
|
|
105
|
+
if (newline === -1)
|
|
106
|
+
break;
|
|
107
|
+
lineStart = newline + 1;
|
|
108
|
+
}
|
|
109
|
+
return { next: text.length, terminated: false };
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Findet jede Stelle, an der `text` mitten durch ein Konstrukt geschnitten
|
|
113
|
+
* ist. Ergebnis ist deterministisch nach Offset sortiert (numerisch, kein
|
|
114
|
+
* `localeCompare`) und auf {@link MAX_IMBALANCES} Einträge begrenzt.
|
|
115
|
+
*/
|
|
116
|
+
export function findDelimiterImbalances(text, options) {
|
|
117
|
+
const found = [];
|
|
118
|
+
const openBrackets = [];
|
|
119
|
+
const { blockComment } = options;
|
|
120
|
+
let i = 0;
|
|
121
|
+
while (i < text.length) {
|
|
122
|
+
if (blockComment !== undefined && text.startsWith(blockComment.open, i)) {
|
|
123
|
+
const close = text.indexOf(blockComment.close, i + blockComment.open.length);
|
|
124
|
+
if (close === -1) {
|
|
125
|
+
found.push({ kind: "unterminated_block_comment", delimiter: blockComment.open, offset: i });
|
|
126
|
+
i = text.length;
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
i = close + blockComment.close.length;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
const lineComment = options.lineComments.find((prefix) => text.startsWith(prefix, i));
|
|
133
|
+
if (lineComment !== undefined) {
|
|
134
|
+
const newline = text.indexOf("\n", i);
|
|
135
|
+
i = newline === -1 ? text.length : newline + 1;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (options.heredocs === "hcl" && text.startsWith("<<", i)) {
|
|
139
|
+
HEREDOC_OPEN.lastIndex = i;
|
|
140
|
+
const match = HEREDOC_OPEN.exec(text);
|
|
141
|
+
if (match !== null) {
|
|
142
|
+
const result = scanHeredoc(text, i, match[0], match[1]);
|
|
143
|
+
if (!result.terminated)
|
|
144
|
+
found.push({ kind: "unterminated_heredoc", delimiter: match[0], offset: i });
|
|
145
|
+
i = result.next;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (options.dollarQuotedStrings === true) {
|
|
150
|
+
const tag = matchDollarQuote(text, i);
|
|
151
|
+
if (tag !== undefined) {
|
|
152
|
+
const result = scanDollarQuoted(text, i, tag);
|
|
153
|
+
if (!result.terminated)
|
|
154
|
+
found.push({ kind: "unterminated_string", delimiter: tag, offset: i });
|
|
155
|
+
i = result.next;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const quote = options.quotes.find((rule) => text.startsWith(rule.open, i));
|
|
160
|
+
if (quote !== undefined) {
|
|
161
|
+
const result = scanQuoted(text, i, quote);
|
|
162
|
+
if (!result.terminated)
|
|
163
|
+
found.push({ kind: "unterminated_string", delimiter: quote.open, offset: i });
|
|
164
|
+
i = Math.max(result.next, i + 1);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
const opening = options.brackets.find((rule) => text.startsWith(rule.open, i));
|
|
168
|
+
if (opening !== undefined) {
|
|
169
|
+
openBrackets.push({ delimiter: opening.open, close: opening.close, offset: i });
|
|
170
|
+
i += opening.open.length;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
const closing = options.brackets.find((rule) => text.startsWith(rule.close, i));
|
|
174
|
+
if (closing !== undefined) {
|
|
175
|
+
const top = openBrackets.at(-1);
|
|
176
|
+
if (top !== undefined && top.close === closing.close) {
|
|
177
|
+
openBrackets.pop();
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
// Ein Schlusszeichen ohne passenden Öffner IM FRAGMENT: die
|
|
181
|
+
// Schnittkante lag hinter dem zugehörigen Öffner.
|
|
182
|
+
found.push({ kind: "unmatched_closing_bracket", delimiter: closing.close, offset: i });
|
|
183
|
+
}
|
|
184
|
+
i += closing.close.length;
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
i += 1;
|
|
188
|
+
}
|
|
189
|
+
for (const open of openBrackets) {
|
|
190
|
+
found.push({ kind: "unclosed_bracket", delimiter: open.delimiter, offset: open.offset });
|
|
191
|
+
}
|
|
192
|
+
return found
|
|
193
|
+
.sort((a, b) => a.offset - b.offset)
|
|
194
|
+
.slice(0, MAX_IMBALANCES)
|
|
195
|
+
.map((entry) => ({ ...entry, line: lineOf(text, entry.offset) }));
|
|
196
|
+
}
|
|
197
|
+
const IMBALANCE_LABELS = {
|
|
198
|
+
unterminated_string: "unterminated string literal opened by",
|
|
199
|
+
unterminated_block_comment: "unterminated block comment opened by",
|
|
200
|
+
unterminated_heredoc: "unterminated heredoc opened by",
|
|
201
|
+
unclosed_bracket: "unclosed bracket",
|
|
202
|
+
unmatched_closing_bracket: "closing bracket without a matching opener in this fragment:",
|
|
203
|
+
};
|
|
204
|
+
/** Einzeilige, menschenlesbare Zusammenfassung für den `contentPreview` eines Ledger-Eintrags. */
|
|
205
|
+
export function describeDelimiterImbalances(imbalances) {
|
|
206
|
+
const parts = imbalances.map((entry) => `${IMBALANCE_LABELS[entry.kind]} ${JSON.stringify(entry.delimiter)} at fragment line ${entry.line}`);
|
|
207
|
+
return `implausible fragment boundary: ${parts.join("; ")}`;
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=delimiter-balance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delimiter-balance.js","sourceRoot":"","sources":["../../src/text/delimiter-balance.ts"],"names":[],"mappings":"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"}
|