doc-detective 4.29.0 → 4.30.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.
Files changed (87) hide show
  1. package/bin/doc-detective-lsp.js +6 -0
  2. package/dist/cli.js +58 -35
  3. package/dist/cli.js.map +1 -1
  4. package/dist/common/src/schemas/schemas.json +56 -56
  5. package/dist/common/src/validate.d.ts +16 -1
  6. package/dist/common/src/validate.d.ts.map +1 -1
  7. package/dist/common/src/validate.js +113 -13
  8. package/dist/common/src/validate.js.map +1 -1
  9. package/dist/core/config.d.ts +66 -1
  10. package/dist/core/config.d.ts.map +1 -1
  11. package/dist/core/config.js +121 -68
  12. package/dist/core/config.js.map +1 -1
  13. package/dist/core/detectTests.d.ts.map +1 -1
  14. package/dist/core/detectTests.js +105 -23
  15. package/dist/core/detectTests.js.map +1 -1
  16. package/dist/core/index.d.ts.map +1 -1
  17. package/dist/core/index.js +53 -14
  18. package/dist/core/index.js.map +1 -1
  19. package/dist/core/openapi.d.ts.map +1 -1
  20. package/dist/core/openapi.js +22 -5
  21. package/dist/core/openapi.js.map +1 -1
  22. package/dist/core/resolveTests.d.ts.map +1 -1
  23. package/dist/core/resolveTests.js +33 -2
  24. package/dist/core/resolveTests.js.map +1 -1
  25. package/dist/core/tests/findStrategies.d.ts.map +1 -1
  26. package/dist/core/tests/findStrategies.js +83 -10
  27. package/dist/core/tests/findStrategies.js.map +1 -1
  28. package/dist/core/tests/saveScreenshot.d.ts.map +1 -1
  29. package/dist/core/tests/saveScreenshot.js +101 -59
  30. package/dist/core/tests/saveScreenshot.js.map +1 -1
  31. package/dist/core/utils.d.ts.map +1 -1
  32. package/dist/core/utils.js +13 -4
  33. package/dist/core/utils.js.map +1 -1
  34. package/dist/index.cjs +356 -196
  35. package/dist/lsp/command.d.ts +12 -0
  36. package/dist/lsp/command.d.ts.map +1 -0
  37. package/dist/lsp/command.js +24 -0
  38. package/dist/lsp/command.js.map +1 -0
  39. package/dist/lsp/completion.d.ts +27 -0
  40. package/dist/lsp/completion.d.ts.map +1 -0
  41. package/dist/lsp/completion.js +114 -0
  42. package/dist/lsp/completion.js.map +1 -0
  43. package/dist/lsp/diagnostics.d.ts +21 -0
  44. package/dist/lsp/diagnostics.d.ts.map +1 -0
  45. package/dist/lsp/diagnostics.js +137 -0
  46. package/dist/lsp/diagnostics.js.map +1 -0
  47. package/dist/lsp/gate.d.ts +30 -0
  48. package/dist/lsp/gate.d.ts.map +1 -0
  49. package/dist/lsp/gate.js +80 -0
  50. package/dist/lsp/gate.js.map +1 -0
  51. package/dist/lsp/hover.d.ts +9 -0
  52. package/dist/lsp/hover.d.ts.map +1 -0
  53. package/dist/lsp/hover.js +56 -0
  54. package/dist/lsp/hover.js.map +1 -0
  55. package/dist/lsp/inline.d.ts +25 -0
  56. package/dist/lsp/inline.d.ts.map +1 -0
  57. package/dist/lsp/inline.js +208 -0
  58. package/dist/lsp/inline.js.map +1 -0
  59. package/dist/lsp/json/positions.d.ts +51 -0
  60. package/dist/lsp/json/positions.d.ts.map +1 -0
  61. package/dist/lsp/json/positions.js +101 -0
  62. package/dist/lsp/json/positions.js.map +1 -0
  63. package/dist/lsp/messages.d.ts +27 -0
  64. package/dist/lsp/messages.d.ts.map +1 -0
  65. package/dist/lsp/messages.js +33 -0
  66. package/dist/lsp/messages.js.map +1 -0
  67. package/dist/lsp/model.d.ts +27 -0
  68. package/dist/lsp/model.d.ts.map +1 -0
  69. package/dist/lsp/model.js +49 -0
  70. package/dist/lsp/model.js.map +1 -0
  71. package/dist/lsp/registry.d.ts +61 -0
  72. package/dist/lsp/registry.d.ts.map +1 -0
  73. package/dist/lsp/registry.js +124 -0
  74. package/dist/lsp/registry.js.map +1 -0
  75. package/dist/lsp/server.d.ts +40 -0
  76. package/dist/lsp/server.d.ts.map +1 -0
  77. package/dist/lsp/server.js +64 -0
  78. package/dist/lsp/server.js.map +1 -0
  79. package/dist/lsp/yaml/positions.d.ts +32 -0
  80. package/dist/lsp/yaml/positions.d.ts.map +1 -0
  81. package/dist/lsp/yaml/positions.js +92 -0
  82. package/dist/lsp/yaml/positions.js.map +1 -0
  83. package/dist/utils.d.ts.map +1 -1
  84. package/dist/utils.js +30 -5
  85. package/dist/utils.js.map +1 -1
  86. package/package.json +6 -2
  87. package/scripts/postinstall.js +144 -1
@@ -0,0 +1,124 @@
1
+ import { schemas } from "../common/src/schemas/index.js";
2
+ /** Collect the candidate sub-schemas of a schema: itself plus anyOf/oneOf/allOf. */
3
+ export function branchesOf(schema) {
4
+ if (!schema || typeof schema !== "object")
5
+ return [];
6
+ const out = [schema];
7
+ for (const key of ["anyOf", "oneOf", "allOf"]) {
8
+ if (Array.isArray(schema[key]))
9
+ out.push(...schema[key]);
10
+ }
11
+ return out;
12
+ }
13
+ /** Dig for a human description across a schema and its immediate branches. */
14
+ export function findDescription(schema) {
15
+ for (const branch of branchesOf(schema)) {
16
+ if (typeof branch.description === "string" && branch.description.length > 0) {
17
+ return branch.description;
18
+ }
19
+ }
20
+ return undefined;
21
+ }
22
+ /** Map a JSON-Schema scalar type onto the snippet-relevant primitive kind. */
23
+ function normalizePrimitive(type) {
24
+ if (type === "string")
25
+ return "string";
26
+ if (type === "number" || type === "integer")
27
+ return "number";
28
+ if (type === "boolean")
29
+ return "boolean";
30
+ return null;
31
+ }
32
+ /**
33
+ * The scalar kind a schema (or a branch) accepts in its compact form, or null.
34
+ * The first primitive type encountered across branches wins.
35
+ */
36
+ export function primitiveKindOf(schema) {
37
+ for (const branch of branchesOf(schema)) {
38
+ const type = branch.type;
39
+ const types = typeof type === "string" ? [type] : Array.isArray(type) ? type : [];
40
+ for (const t of types) {
41
+ const kind = normalizePrimitive(t);
42
+ if (kind)
43
+ return kind;
44
+ }
45
+ }
46
+ return null;
47
+ }
48
+ /** Does the schema (or a branch) accept a primitive scalar value? */
49
+ export function acceptsPrimitive(schema) {
50
+ return primitiveKindOf(schema) !== null;
51
+ }
52
+ /** Merge the `properties` maps found across a schema's object branches. */
53
+ export function collectFields(schema) {
54
+ const seen = new Map();
55
+ for (const branch of branchesOf(schema)) {
56
+ const props = branch.properties;
57
+ if (!props || typeof props !== "object")
58
+ continue;
59
+ for (const [name, propSchema] of Object.entries(props)) {
60
+ if (name === "$schema" || seen.has(name))
61
+ continue;
62
+ seen.set(name, {
63
+ name,
64
+ description: findDescription(propSchema),
65
+ primitiveKind: primitiveKindOf(propSchema),
66
+ enumValues: extractEnum(propSchema),
67
+ });
68
+ }
69
+ }
70
+ return [...seen.values()];
71
+ }
72
+ /** Pull an enum list from a schema or its branches, if any. */
73
+ export function extractEnum(schema) {
74
+ for (const branch of branchesOf(schema)) {
75
+ if (Array.isArray(branch.enum))
76
+ return branch.enum.slice();
77
+ }
78
+ return undefined;
79
+ }
80
+ /**
81
+ * The `allOf` element of a `step_v3` anyOf branch that carries the action: the
82
+ * one whose `required` names exactly the action key (never `$schema`).
83
+ */
84
+ function actionPartOf(branch) {
85
+ const parts = Array.isArray(branch.allOf) ? branch.allOf : [branch];
86
+ return parts.find((p) => Array.isArray(p.required) &&
87
+ p.required.length === 1 &&
88
+ p.required[0] !== "$schema");
89
+ }
90
+ /**
91
+ * Build the action registry from the live `step_v3` schema. Derived at runtime
92
+ * (not a build step) so a new action added to the schemas automatically appears
93
+ * in completion/hover — the anti-drift test pins that guarantee.
94
+ */
95
+ export function buildRegistry(step = schemas["step_v3"]) {
96
+ const actions = [];
97
+ for (const branch of step.anyOf || []) {
98
+ const part = actionPartOf(branch);
99
+ /* c8 ignore next - every step_v3 anyOf branch has an action part; defensive */
100
+ if (!part)
101
+ continue;
102
+ const key = part.required[0];
103
+ const propSchema = part.properties?.[key];
104
+ const primitiveKind = primitiveKindOf(propSchema);
105
+ actions.push({
106
+ key,
107
+ title: part.title || key,
108
+ description: findDescription(propSchema),
109
+ acceptsPrimitive: primitiveKind !== null,
110
+ primitiveKind,
111
+ fields: collectFields(propSchema),
112
+ });
113
+ }
114
+ const byKey = new Map(actions.map((a) => [a.key, a]));
115
+ return { actions, byKey };
116
+ }
117
+ /** Lazily-built shared registry (the schemas are static within a process). */
118
+ let cached;
119
+ export function getRegistry() {
120
+ if (!cached)
121
+ cached = buildRegistry();
122
+ return cached;
123
+ }
124
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/lsp/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import { type InitializeResult } from "vscode-languageserver/node.js";
2
+ import type { CompletionItem, CompletionParams, Hover, HoverParams } from "vscode-languageserver";
3
+ import { TextDocument } from "vscode-languageserver-textdocument";
4
+ /**
5
+ * The subset of a `Connection` the handlers touch. Narrowed to an interface so
6
+ * tests can drive the wiring with a fake instead of a live stdio transport.
7
+ */
8
+ export interface DiagnosticsConnection {
9
+ onInitialize(handler: () => InitializeResult): void;
10
+ sendDiagnostics(params: {
11
+ uri: string;
12
+ diagnostics: unknown[];
13
+ }): void;
14
+ onCompletion(handler: (params: CompletionParams) => CompletionItem[]): void;
15
+ onHover(handler: (params: HoverParams) => Hover | null): void;
16
+ }
17
+ /**
18
+ * The subset of a `TextDocuments` manager the handlers subscribe to.
19
+ */
20
+ export interface DocumentEvents {
21
+ onDidChangeContent(handler: (event: {
22
+ document: TextDocument;
23
+ }) => void): void;
24
+ onDidClose(handler: (event: {
25
+ document: TextDocument;
26
+ }) => void): void;
27
+ get(uri: string): TextDocument | undefined;
28
+ }
29
+ /**
30
+ * Wire language-server behavior onto a connection + document manager. Pure of
31
+ * any transport, so a unit test can pass fakes, capture the registered
32
+ * callbacks, and assert what gets published — no real process required.
33
+ */
34
+ export declare function registerHandlers(connection: DiagnosticsConnection, documents: DocumentEvents): void;
35
+ /**
36
+ * Boot the language server over stdio. Called by the `doc-detective lsp`
37
+ * subcommand.
38
+ */
39
+ export declare function startServer(): void;
40
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/lsp/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,gBAAgB,EACtB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAChB,KAAK,EACL,WAAW,EACZ,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAKlE;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,YAAY,CAAC,OAAO,EAAE,MAAM,gBAAgB,GAAG,IAAI,CAAC;IACpD,eAAe,CAAC,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,OAAO,EAAE,CAAA;KAAE,GAAG,IAAI,CAAC;IACvE,YAAY,CACV,OAAO,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,cAAc,EAAE,GACtD,IAAI,CAAC;IACR,OAAO,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,KAAK,GAAG,IAAI,GAAG,IAAI,CAAC;CAC/D;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,kBAAkB,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,YAAY,CAAA;KAAE,KAAK,IAAI,GAAG,IAAI,CAAC;IAC/E,UAAU,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,YAAY,CAAA;KAAE,KAAK,IAAI,GAAG,IAAI,CAAC;IACvE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC;CAC5C;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,qBAAqB,EACjC,SAAS,EAAE,cAAc,GACxB,IAAI,CAsCN;AAKD;;;GAGG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAclC"}
@@ -0,0 +1,64 @@
1
+ import { createConnection, TextDocuments, ProposedFeatures, StreamMessageReader, StreamMessageWriter, TextDocumentSyncKind, } from "vscode-languageserver/node.js";
2
+ import { TextDocument } from "vscode-languageserver-textdocument";
3
+ import { computeDiagnostics } from "./diagnostics.js";
4
+ import { computeCompletions } from "./completion.js";
5
+ import { computeHover } from "./hover.js";
6
+ /**
7
+ * Wire language-server behavior onto a connection + document manager. Pure of
8
+ * any transport, so a unit test can pass fakes, capture the registered
9
+ * callbacks, and assert what gets published — no real process required.
10
+ */
11
+ export function registerHandlers(connection, documents) {
12
+ connection.onInitialize(() => ({
13
+ capabilities: {
14
+ // Full sync keeps Phase 1 simple; jsonc-parser reparses the whole buffer
15
+ // on each change anyway, so incremental patching buys nothing yet.
16
+ textDocumentSync: TextDocumentSyncKind.Full,
17
+ completionProvider: { triggerCharacters: ['"', "{"] },
18
+ hoverProvider: true,
19
+ },
20
+ }));
21
+ const publish = (document) => {
22
+ connection.sendDiagnostics({
23
+ uri: document.uri,
24
+ diagnostics: computeDiagnostics(document),
25
+ });
26
+ };
27
+ // Fires on open and on every edit — the single hook we need for live
28
+ // diagnostics.
29
+ documents.onDidChangeContent((event) => publish(event.document));
30
+ // Clear diagnostics when a document closes so stale squiggles don't linger.
31
+ documents.onDidClose((event) => connection.sendDiagnostics({ uri: event.document.uri, diagnostics: [] }));
32
+ connection.onCompletion((params) => {
33
+ const document = documents.get(params.textDocument.uri);
34
+ if (!document)
35
+ return [];
36
+ return computeCompletions(document, params.position);
37
+ });
38
+ connection.onHover((params) => {
39
+ const document = documents.get(params.textDocument.uri);
40
+ if (!document)
41
+ return null;
42
+ return computeHover(document, params.position);
43
+ });
44
+ }
45
+ /* c8 ignore start - real stdio bootstrap: no injectable seam; the pure wiring
46
+ in registerHandlers is unit-tested, and the whole server is exercised
47
+ end-to-end by the spawned protocol test. */
48
+ /**
49
+ * Boot the language server over stdio. Called by the `doc-detective lsp`
50
+ * subcommand.
51
+ */
52
+ export function startServer() {
53
+ // Explicit stdio streams so the server works no matter how it's launched —
54
+ // the `doc-detective lsp` subcommand OR the bare `doc-detective-lsp` bin.
55
+ // (createConnection(ProposedFeatures.all) alone sniffs argv for `--stdio`,
56
+ // which the bare bin doesn't pass.)
57
+ const connection = createConnection(ProposedFeatures.all, new StreamMessageReader(process.stdin), new StreamMessageWriter(process.stdout));
58
+ const documents = new TextDocuments(TextDocument);
59
+ registerHandlers(connection, documents);
60
+ documents.listen(connection);
61
+ connection.listen();
62
+ }
63
+ /* c8 ignore stop */
64
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/lsp/server.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,GAGrB,MAAM,+BAA+B,CAAC;AAOvC,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAwB1C;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAC9B,UAAiC,EACjC,SAAyB;IAEzB,UAAU,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,CAAC;QAC7B,YAAY,EAAE;YACZ,yEAAyE;YACzE,mEAAmE;YACnE,gBAAgB,EAAE,oBAAoB,CAAC,IAAI;YAC3C,kBAAkB,EAAE,EAAE,iBAAiB,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE;YACrD,aAAa,EAAE,IAAI;SACpB;KACF,CAAC,CAAC,CAAC;IAEJ,MAAM,OAAO,GAAG,CAAC,QAAsB,EAAE,EAAE;QACzC,UAAU,CAAC,eAAe,CAAC;YACzB,GAAG,EAAE,QAAQ,CAAC,GAAG;YACjB,WAAW,EAAE,kBAAkB,CAAC,QAAQ,CAAC;SAC1C,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,qEAAqE;IACrE,eAAe;IACf,SAAS,CAAC,kBAAkB,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEjE,4EAA4E;IAC5E,SAAS,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,EAAE,CAC7B,UAAU,CAAC,eAAe,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CACzE,CAAC;IAEF,UAAU,CAAC,YAAY,CAAC,CAAC,MAAM,EAAE,EAAE;QACjC,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACxD,IAAI,CAAC,QAAQ;YAAE,OAAO,EAAE,CAAC;QACzB,OAAO,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,UAAU,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;QAC5B,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACxD,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC3B,OAAO,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;8CAE8C;AAC9C;;;GAGG;AACH,MAAM,UAAU,WAAW;IACzB,2EAA2E;IAC3E,0EAA0E;IAC1E,2EAA2E;IAC3E,oCAAoC;IACpC,MAAM,UAAU,GAAe,gBAAgB,CAC7C,gBAAgB,CAAC,GAAG,EACpB,IAAI,mBAAmB,CAAC,OAAO,CAAC,KAAK,CAAC,EACtC,IAAI,mBAAmB,CAAC,OAAO,CAAC,MAAM,CAAC,CACxC,CAAC;IACF,MAAM,SAAS,GAAG,IAAI,aAAa,CAAC,YAAY,CAAC,CAAC;IAClD,gBAAgB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IACxC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC7B,UAAU,CAAC,MAAM,EAAE,CAAC;AACtB,CAAC;AACD,oBAAoB"}
@@ -0,0 +1,32 @@
1
+ import YAML from "yaml";
2
+ import type { OffsetRange, ActionKeyedStep } from "../json/positions.js";
3
+ /** Result of parsing YAML: the document (for node lookups) plus its value. */
4
+ export interface YamlParse {
5
+ doc: YAML.Document.Parsed;
6
+ value: any;
7
+ /** Set when `doc.toJS()` threw (e.g. an alias-bomb exceeding maxAliasCount). */
8
+ valueError?: string;
9
+ }
10
+ /** Parse YAML into a position-preserving document plus its plain JS value. */
11
+ export declare function parseYamlTree(text: string): YamlParse;
12
+ /** A YAML syntax error reduced to an offset span and message. */
13
+ export interface YamlSyntaxError {
14
+ range: OffsetRange;
15
+ message: string;
16
+ }
17
+ /** Collect YAML syntax errors as offset spans (empty when the doc is clean). */
18
+ export declare function yamlSyntaxErrors(doc: YAML.Document.Parsed): YamlSyntaxError[];
19
+ /**
20
+ * Resolve the source span for an AJV `instancePath` in a YAML document. Walks
21
+ * up to the nearest present ancestor (like the JSON resolver) so a
22
+ * `required`-style error still anchors somewhere. Returns null only when even
23
+ * the document contents can't be located.
24
+ */
25
+ export declare function rangeForInstancePathYaml(doc: YAML.Document.Parsed, instancePath: string): OffsetRange | null;
26
+ /**
27
+ * Find every step written as a map carrying an `action` key inside a `steps`
28
+ * sequence — the YAML twin of the JSON detector. Returns the offending `action`
29
+ * key span and the step's JSON-Pointer.
30
+ */
31
+ export declare function findActionKeyedStepsYaml(doc: YAML.Document.Parsed): ActionKeyedStep[];
32
+ //# sourceMappingURL=positions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"positions.d.ts","sourceRoot":"","sources":["../../../src/lsp/yaml/positions.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGzE,8EAA8E;AAC9E,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;IAC1B,KAAK,EAAE,GAAG,CAAC;IACX,gFAAgF;IAChF,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAarD;AAED,iEAAiE;AACjE,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,eAAe,EAAE,CAK7E;AASD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,EACzB,YAAY,EAAE,MAAM,GACnB,WAAW,GAAG,IAAI,CAUpB;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,GACxB,eAAe,EAAE,CAqCnB"}
@@ -0,0 +1,92 @@
1
+ import YAML from "yaml";
2
+ import { instancePathToSegments, pointerFromPath } from "../json/positions.js";
3
+ /** Parse YAML into a position-preserving document plus its plain JS value. */
4
+ export function parseYamlTree(text) {
5
+ const doc = YAML.parseDocument(text, { keepSourceTokens: true });
6
+ // `toJS()` resolves aliases and can throw on a pathological document (the
7
+ // "billion laughs" alias bomb the yaml lib guards with maxAliasCount). Catch
8
+ // it so a malicious/degenerate buffer can't crash the server — surface it as
9
+ // a document-level error instead.
10
+ try {
11
+ return { doc, value: doc.toJS() };
12
+ }
13
+ catch (error) {
14
+ /* c8 ignore next - the yaml lib always throws an Error with a message; the String() fallback guards a hypothetical non-Error throw */
15
+ const message = error instanceof Error ? error.message : String(error);
16
+ return { doc, value: undefined, valueError: message };
17
+ }
18
+ }
19
+ /** Collect YAML syntax errors as offset spans (empty when the doc is clean). */
20
+ export function yamlSyntaxErrors(doc) {
21
+ return doc.errors.map((error) => {
22
+ const [start, end] = error.pos;
23
+ return { range: { start, end }, message: error.message };
24
+ });
25
+ }
26
+ /** Node range → OffsetRange, using [start, valueEnd] for a tight span. */
27
+ function nodeRange(node) {
28
+ const range = node?.range;
29
+ if (!Array.isArray(range))
30
+ return null;
31
+ return { start: range[0], end: range[1] };
32
+ }
33
+ /**
34
+ * Resolve the source span for an AJV `instancePath` in a YAML document. Walks
35
+ * up to the nearest present ancestor (like the JSON resolver) so a
36
+ * `required`-style error still anchors somewhere. Returns null only when even
37
+ * the document contents can't be located.
38
+ */
39
+ export function rangeForInstancePathYaml(doc, instancePath) {
40
+ const segments = instancePathToSegments(instancePath);
41
+ for (let end = segments.length; end >= 0; end--) {
42
+ const node = end === 0 ? doc.contents : doc.getIn(segments.slice(0, end), true);
43
+ const range = nodeRange(node);
44
+ if (range)
45
+ return range;
46
+ }
47
+ // Reached only for an empty document (no contents node has a range).
48
+ return null;
49
+ }
50
+ /**
51
+ * Find every step written as a map carrying an `action` key inside a `steps`
52
+ * sequence — the YAML twin of the JSON detector. Returns the offending `action`
53
+ * key span and the step's JSON-Pointer.
54
+ */
55
+ export function findActionKeyedStepsYaml(doc) {
56
+ const found = [];
57
+ const visit = (node, path) => {
58
+ if (YAML.isMap(node)) {
59
+ for (const pair of node.items) {
60
+ const key = pair.key?.value;
61
+ if (key === "steps" && YAML.isSeq(pair.value)) {
62
+ collectSteps(pair.value, [...path, "steps"]);
63
+ }
64
+ if (pair.value)
65
+ visit(pair.value, [...path, key]);
66
+ }
67
+ }
68
+ else if (YAML.isSeq(node)) {
69
+ node.items.forEach((item, index) => visit(item, [...path, index]));
70
+ }
71
+ };
72
+ const collectSteps = (seq, seqPath) => {
73
+ seq.items.forEach((item, index) => {
74
+ if (!YAML.isMap(item))
75
+ return;
76
+ const actionPair = item.items.find((p) => p.key?.value === "action");
77
+ if (actionPair) {
78
+ const range = nodeRange(actionPair.key);
79
+ if (range) {
80
+ found.push({
81
+ keyRange: range,
82
+ pointer: pointerFromPath([...seqPath, index]),
83
+ });
84
+ }
85
+ }
86
+ });
87
+ };
88
+ if (doc.contents)
89
+ visit(doc.contents, []);
90
+ return found;
91
+ }
92
+ //# sourceMappingURL=positions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"positions.js","sourceRoot":"","sources":["../../../src/lsp/yaml/positions.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAcA,OAAO,EACL,UAAU,EACV,OAAO,EACP,SAAS,EACT,aAAa,EACb,YAAY,EACZ,OAAO,EACP,cAAc,EACd,GAAG,EACH,eAAe,EACf,uBAAuB,EACvB,aAAa,EACb,SAAS,EACT,gBAAgB,EAChB,gBAAgB,GACjB,CAAC;AASF,iBAAS,gBAAgB,IAAI,OAAO,CAKnC;AAQD,iBAAS,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,GAAQ,GAAG,OAAO,CAMjE;AAED,iBAAS,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,GAAE,MAAe,EAAE,MAAM,GAAE,GAAQ,QASlE;AAMD,iBAAS,UAAU,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG,CAiGlC;AAGD,iBAAS,OAAO,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG,CAG/B;AAGD,iBAAe,uBAAuB,CAAC,MAAM,GAAE,GAAQ;;;UAyEtD;AA8CD,iBAAe,SAAS,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE;IAAE,UAAU,CAAC,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,GAAG,CAAA;CAAE,gBAwM7E;AAgCD,QAAA,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAilBzG,CAAC;AAGF,iBAAS,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,WAM5D;AAED,iBAAe,aAAa,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE;IAAE,SAAS,EAAE,GAAG,CAAC;IAAC,OAAO,EAAE,GAAG,CAAA;CAAE,iBA8DpF;AAED,iBAAe,aAAa,CAAC,MAAM,EAAE,GAAG,YAAK,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,GAAE,GAAQ,kBA0D9F;AAGD,iBAAe,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE;;;;GAwCvD;AAED,iBAAS,OAAO,SAuBf;AAGD,iBAAS,cAAc,QA+GtB"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAcA,OAAO,EACL,UAAU,EACV,OAAO,EACP,SAAS,EACT,aAAa,EACb,YAAY,EACZ,OAAO,EACP,cAAc,EACd,GAAG,EACH,eAAe,EACf,uBAAuB,EACvB,aAAa,EACb,SAAS,EACT,gBAAgB,EAChB,gBAAgB,GACjB,CAAC;AASF,iBAAS,gBAAgB,IAAI,OAAO,CAKnC;AAQD,iBAAS,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,GAAQ,GAAG,OAAO,CAMjE;AAED,iBAAS,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,GAAE,MAAe,EAAE,MAAM,GAAE,GAAQ,QASlE;AAMD,iBAAS,UAAU,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG,CAiGlC;AAGD,iBAAS,OAAO,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG,CAG/B;AAGD,iBAAe,uBAAuB,CAAC,MAAM,GAAE,GAAQ;;;UAyEtD;AA8CD,iBAAe,SAAS,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE;IAAE,UAAU,CAAC,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,GAAG,CAAA;CAAE,gBAwM7E;AAgCD,QAAA,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CA+lBzG,CAAC;AAGF,iBAAS,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,WAM5D;AAED,iBAAe,aAAa,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE;IAAE,SAAS,EAAE,GAAG,CAAC;IAAC,OAAO,EAAE,GAAG,CAAA;CAAE,iBA4DpF;AAED,iBAAe,aAAa,CAAC,MAAM,EAAE,GAAG,YAAK,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,GAAE,GAAQ,kBA0E9F;AAGD,iBAAe,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE;;;;GAwCvD;AAED,iBAAS,OAAO,SAuBf;AAGD,iBAAS,cAAc,QA+GtB"}
package/dist/utils.js CHANGED
@@ -454,7 +454,12 @@ const reporters = {
454
454
  const outputExtensions = [".json"];
455
455
  // Normalize output path
456
456
  outputPath = path.resolve(outputPath);
457
- const data = JSON.stringify(results, null, 2);
457
+ // Reuse the results JSON serialized once by outputResults when present
458
+ // (byte-identical to serializing `results` here); fall back for direct
459
+ // callers that don't pass it.
460
+ const data = typeof options.resultsJson === "string"
461
+ ? options.resultsJson
462
+ : JSON.stringify(results, null, 2);
458
463
  let outputFile = "";
459
464
  let outputDir = "";
460
465
  let reportType = "doc-detective-results";
@@ -564,10 +569,17 @@ const reporters = {
564
569
  // The run folder name IS the runId under the `runs/<id>` layout.
565
570
  runId: path.basename(runDir),
566
571
  };
572
+ // When we archive the unmodified `results` (stamped-runDir case), reuse the
573
+ // JSON outputResults already serialized. When we rewrote runId/runDir into a
574
+ // fresh copy, that object differs from `results`, so serialize it directly —
575
+ // keeping the written file byte-identical to before this optimization.
576
+ const persistedJson = useStampedRunDir && typeof options.resultsJson === "string"
577
+ ? options.resultsJson
578
+ : JSON.stringify(persistedResults, null, 2);
567
579
  const outputFile = path.resolve(runDir, `${reportType}.json`);
568
580
  try {
569
581
  fs.mkdirSync(runDir, { recursive: true });
570
- fs.writeFileSync(outputFile, JSON.stringify(persistedResults, null, 2));
582
+ fs.writeFileSync(outputFile, persistedJson);
571
583
  // Archive a human-readable HTML report beside the JSON, so the run folder
572
584
  // is a complete shareable artifact without the standalone `html` reporter.
573
585
  // Best-effort and isolated: an HTML failure must not break the JSON
@@ -978,7 +990,6 @@ async function reportResults({ apiConfig, results }) {
978
990
  try {
979
991
  const url = `${apiConfig.url}/contexts`;
980
992
  const payload = { contexts };
981
- console.log(payload);
982
993
  const response = await axios.post(url, payload, {
983
994
  headers: {
984
995
  "x-runner-token": apiConfig.token,
@@ -1021,15 +1032,29 @@ async function outputResults(config = {}, outputPath, results, options = {}) {
1021
1032
  return reporter;
1022
1033
  });
1023
1034
  }
1035
+ // Serialize the canonical results tree ONCE and share the string with the
1036
+ // JSON-writing reporters (json + runFolder) instead of each calling
1037
+ // JSON.stringify on the full tree independently. Only computed when a
1038
+ // JSON-writing reporter is actually active, so a terminal-only run pays
1039
+ // nothing. Each reporter still falls back to serializing itself when the
1040
+ // shared string is absent (so they stay correct if called directly), and
1041
+ // runFolder only reuses it when it archives the unmodified `results` (the
1042
+ // stamped-runDir case) — a rewritten runId/runDir copy is serialized fresh,
1043
+ // keeping every written file byte-identical to before.
1044
+ const writesJson = activeReporters.includes("jsonReporter") ||
1045
+ activeReporters.includes("runFolderReporter");
1046
+ const reporterOptions = writesJson
1047
+ ? { ...options, resultsJson: JSON.stringify(results, null, 2) }
1048
+ : options;
1024
1049
  // Execute each reporter
1025
1050
  const reporterPromises = activeReporters.map((reporter) => {
1026
1051
  if (typeof reporter === "function") {
1027
1052
  // Direct function reference
1028
- return reporter(config, outputPath, results, options);
1053
+ return reporter(config, outputPath, results, reporterOptions);
1029
1054
  }
1030
1055
  else if (typeof reporter === "string" && reporters[reporter]) {
1031
1056
  // String reference to built-in or registered reporter
1032
- return reporters[reporter](config, outputPath, results, options);
1057
+ return reporters[reporter](config, outputPath, results, reporterOptions);
1033
1058
  }
1034
1059
  else if (typeof reporter === "string" && !reporters[reporter]) {
1035
1060
  console.error(`Reporter "${reporter}" not found. Available reporters: ${Object.keys(reporters).join(", ")}`);