sqllens 1.10.1 → 1.11.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/README.md +5 -1
- package/dist/api.d.ts +1 -0
- package/dist/api.js +3 -0
- package/dist/document/document.js +2 -1
- package/dist/document/spans.d.ts +14 -0
- package/dist/document/spans.js +34 -0
- package/dist/document/split.d.ts +11 -1
- package/dist/document/split.js +72 -32
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/minijinja/engine.js +2 -1
- package/dist/minijinja/parse.d.ts +4 -0
- package/dist/minijinja/parse.js +12 -0
- package/dist/template/engine.d.ts +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -367,7 +367,11 @@ that run on incomplete, mid-edit text. They never need a clean parse:
|
|
|
367
367
|
- `SqlDocument` is a persistent, immutable, position-addressable per-file model.
|
|
368
368
|
It runs `parse → resolveScopes` once (plus lazy `analyze(schema)`), caches the
|
|
369
369
|
result, and answers `tokenAt` / `nodeAt`. An edit yields a new document; an
|
|
370
|
-
O(log n) `LineIndex` maps positions to offsets.
|
|
370
|
+
O(log n) `LineIndex` maps positions to offsets. Its `statements` are the
|
|
371
|
+
per-statement cells; each cell's `span` carries the separator token that ends
|
|
372
|
+
it (`;`, or the `GO` word), so the statement's own text ends where that starts.
|
|
373
|
+
- `statementSpans(text, dialect, { templating? })`: the same cell spans without
|
|
374
|
+
the per-cell parses, for code lenses and run-at-cursor ranges on every change.
|
|
371
375
|
- `completeAt(doc, offset, schema?)`: scope-aware completion (keywords, columns,
|
|
372
376
|
tables, functions) from an ATN (Augmented Transition Network, the grammar's
|
|
373
377
|
state-machine form) candidate walk over the grammar, our own, with no third-party
|
package/dist/api.d.ts
CHANGED
|
@@ -116,6 +116,7 @@ export type { Token, TokenRole } from "./token/token.js";
|
|
|
116
116
|
export { SqlDocument, type DocumentAnalysis, type StatementCell, type DocumentVariant, type UnionCte, } from "./document/document.js";
|
|
117
117
|
export { LineIndex } from "./document/line-index.js";
|
|
118
118
|
export type { StatementCellSpan } from "./document/split.js";
|
|
119
|
+
export { statementSpans } from "./document/spans.js";
|
|
119
120
|
export { complete, completeAt, type Completion, type CompletionResult, type ReplaceRange, type CompleteOptions, type CandidateIdentity, type CandidateDecoration, type DecorateCandidate, } from "./completion/complete.js";
|
|
120
121
|
export { jinjaSlotAt, type JinjaSlot } from "./completion/jinja-slot.js";
|
|
121
122
|
export { signatureAt, type SignatureHelpInfo, type SignatureLabel } from "./signature/signature.js";
|
package/dist/api.js
CHANGED
|
@@ -202,6 +202,9 @@ export { tokenize } from "./token/tokenize.js";
|
|
|
202
202
|
// these at call time, never at module-eval time.
|
|
203
203
|
export { SqlDocument, } from "./document/document.js";
|
|
204
204
|
export { LineIndex } from "./document/line-index.js";
|
|
205
|
+
// The cell spans alone (plain or templated), for a consumer that needs statement ranges without
|
|
206
|
+
// the per-cell parses; identical to the spans the document's cells carry.
|
|
207
|
+
export { statementSpans } from "./document/spans.js";
|
|
205
208
|
// Scope-aware completion over a SqlDocument — the broken-input editor feature (keywords + schema
|
|
206
209
|
// tables/columns + function names at the caret). Total: never throws.
|
|
207
210
|
export { complete, completeAt, } from "./completion/complete.js";
|
|
@@ -168,7 +168,8 @@ export class SqlDocument {
|
|
|
168
168
|
const r = whole.cached.templated;
|
|
169
169
|
const spans = opts.templating.parseCell ? splitStatements(r.placeholder, dialect) : [whole.cell.span];
|
|
170
170
|
if (spans.length === 1) {
|
|
171
|
-
|
|
171
|
+
// The whole-text cell, under the split's own span so it carries its separator.
|
|
172
|
+
cells = [Object.freeze({ ...whole.cell, span: spans[0] })];
|
|
172
173
|
backing = [whole.cached];
|
|
173
174
|
templated = r;
|
|
174
175
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Dialect } from "../dialect.js";
|
|
2
|
+
import type { TemplateProvider } from "../qualify/template-provider.js";
|
|
3
|
+
import type { TemplateEngine } from "../template/engine.js";
|
|
4
|
+
import { type StatementCellSpan } from "./split.js";
|
|
5
|
+
/**
|
|
6
|
+
* The statement cell spans `SqlDocument.create(text, dialect, opts)` would produce, without the
|
|
7
|
+
* per-cell parses. Plain text splits directly; with `templating` the engine's placeholder is
|
|
8
|
+
* split (its `placeholder` hook when it has one, else its full `parse`), and an engine without
|
|
9
|
+
* `parseCell` answers one whole-text span, exactly as the document door does. Total: never throws.
|
|
10
|
+
*/
|
|
11
|
+
export declare function statementSpans(text: string, dialect: Dialect, opts?: {
|
|
12
|
+
templating?: TemplateEngine;
|
|
13
|
+
provider?: TemplateProvider;
|
|
14
|
+
}): StatementCellSpan[];
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// statementSpans() — the statement cell spans of a text without building the
|
|
3
|
+
// document. The SqlDocument constructor derives its cells from exactly this
|
|
4
|
+
// split (the plain text, or the engine's placeholder for a templated one), so
|
|
5
|
+
// the spans answered here are the spans `doc.statements[i].span` would carry;
|
|
6
|
+
// a consumer that only needs "where do the statements start and end" (code
|
|
7
|
+
// lenses, run-at-cursor ranges) pays the lex and the split, not the parses.
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
import { debugRethrow } from "../debug.js";
|
|
10
|
+
import { splitStatements } from "./split.js";
|
|
11
|
+
/**
|
|
12
|
+
* The statement cell spans `SqlDocument.create(text, dialect, opts)` would produce, without the
|
|
13
|
+
* per-cell parses. Plain text splits directly; with `templating` the engine's placeholder is
|
|
14
|
+
* split (its `placeholder` hook when it has one, else its full `parse`), and an engine without
|
|
15
|
+
* `parseCell` answers one whole-text span, exactly as the document door does. Total: never throws.
|
|
16
|
+
*/
|
|
17
|
+
export function statementSpans(text, dialect, opts = {}) {
|
|
18
|
+
const engine = opts.templating;
|
|
19
|
+
if (!engine)
|
|
20
|
+
return splitStatements(text, dialect);
|
|
21
|
+
if (!engine.parseCell)
|
|
22
|
+
return [{ start: 0, end: text.length }];
|
|
23
|
+
let placeholder;
|
|
24
|
+
try {
|
|
25
|
+
placeholder = engine.placeholder
|
|
26
|
+
? engine.placeholder(text, dialect, { provider: opts.provider })
|
|
27
|
+
: engine.parse(text, dialect, { provider: opts.provider }).placeholder;
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
debugRethrow(e);
|
|
31
|
+
placeholder = text;
|
|
32
|
+
}
|
|
33
|
+
return splitStatements(placeholder, dialect);
|
|
34
|
+
}
|
package/dist/document/split.d.ts
CHANGED
|
@@ -5,13 +5,23 @@ export interface StatementCellSpan {
|
|
|
5
5
|
/** doc offset, exclusive — includes the trailing separator (`;` / GO line); the document's last
|
|
6
6
|
* cell also includes whatever trivia follows its separator, up to `text.length`. */
|
|
7
7
|
end: number;
|
|
8
|
+
/** The separator token that terminates this cell, as doc offsets (`start` inclusive, `end`
|
|
9
|
+
* exclusive): the `;`, or the `GO` word itself (not its line). Absent when the cell has no
|
|
10
|
+
* separator (an unterminated final statement, a separator-free document, the whole-document
|
|
11
|
+
* fallback). The statement's own text ends where this starts, before any trailing trivia. */
|
|
12
|
+
separator?: {
|
|
13
|
+
start: number;
|
|
14
|
+
end: number;
|
|
15
|
+
};
|
|
8
16
|
}
|
|
9
17
|
/**
|
|
10
18
|
* Split `text` into top-level statement cells using `tokenize(text, dialect)`.
|
|
11
19
|
* Total: never throws. Splits at channel-0 `;` at compound depth 0 (BEGIN/CASE
|
|
12
20
|
* increment, END decrements, floor 0; a T-SQL `BEGIN TRAN`/`TRANSACTION`/
|
|
13
21
|
* `DISTRIBUTED` does not open a depth level) plus, for T-SQL, a `GO` batch
|
|
14
|
-
* separator alone on its line
|
|
22
|
+
* separator alone on its line; text ending inside an open level splits at every
|
|
23
|
+
* separator from the unclosed opener on (see `findSplitEnds`). Each cell carries
|
|
24
|
+
* the separator token that ends it. Returns the whole doc as one cell when
|
|
15
25
|
* splitting is unsafe (the tiling invariant fails) or pointless (no separators).
|
|
16
26
|
*/
|
|
17
27
|
export declare function splitStatements(text: string, dialect: Dialect): StatementCellSpan[];
|
package/dist/document/split.js
CHANGED
|
@@ -26,14 +26,43 @@ const NON_OPENER_END_SUFFIXES = new Set(["IF", "WHILE", "FOR", "LOOP", "REPEAT"]
|
|
|
26
26
|
function wholeDoc(text) {
|
|
27
27
|
return [{ start: 0, end: text.length }];
|
|
28
28
|
}
|
|
29
|
-
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
|
|
29
|
+
/** The split point a `;` or a T-SQL `GO` at `channel0[i]` makes, ignoring depth, or undefined when
|
|
30
|
+
* the token is neither. A GO batch separator must sit alone on its line among channel-0 tokens
|
|
31
|
+
* (otherwise it is an identifier/alias use of the word); its cell end is the end of that line. */
|
|
32
|
+
function separatorAt(text, channel0, i, dialect) {
|
|
33
|
+
const t = channel0[i];
|
|
34
|
+
const separator = { start: t.start, end: t.stop + 1 };
|
|
35
|
+
if (t.text === ";")
|
|
36
|
+
return { end: t.stop + 1, separator };
|
|
37
|
+
if (dialect === "tsql" && t.text.toUpperCase() === "GO") {
|
|
38
|
+
const prev = channel0[i - 1];
|
|
39
|
+
const next = channel0[i + 1];
|
|
40
|
+
const alone = (!prev || prev.line !== t.line) && (!next || next.line !== t.line);
|
|
41
|
+
if (!alone)
|
|
42
|
+
return undefined;
|
|
43
|
+
const nl = text.indexOf("\n", t.stop + 1);
|
|
44
|
+
return { end: nl === -1 ? text.length : nl + 1, separator };
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
/** Every top-level split point in `text`, in ascending order, plus `tail`: the separator of a
|
|
49
|
+
* terminated final statement that nothing real follows (only whitespace, comments, the final
|
|
50
|
+
* newline). That separator is not a split end, the trivia after it belongs to the cell it
|
|
51
|
+
* terminates, so a single terminated statement is one cell rather than a statement plus a
|
|
52
|
+
* token-less tail cell; `tail` lets that cell still carry its separator.
|
|
53
|
+
*
|
|
54
|
+
* Depth: `BEGIN`/`CASE` open a level, `END` closes one, and only a separator at depth 0 splits.
|
|
55
|
+
* When the text ends INSIDE an open level (an unclosed CASE mid-typing, jinja arms that leave
|
|
56
|
+
* the placeholder with more openers than closers), the walk cannot know where that block ends,
|
|
57
|
+
* and one cell silently spanning several statements is the worse failure (a "run statement at
|
|
58
|
+
* cursor" would run them all): the split points before the outermost unclosed opener stand, and
|
|
59
|
+
* from that opener on every separator splits regardless of depth. Balanced text is unaffected. */
|
|
33
60
|
function findSplitEnds(text, tokens, dialect) {
|
|
34
61
|
const channel0 = tokens.filter((t) => t.channel === 0);
|
|
35
|
-
|
|
62
|
+
let ends = [];
|
|
36
63
|
let depth = 0;
|
|
64
|
+
/** The outermost currently-open level: where it opened and how many split points preceded it. */
|
|
65
|
+
let opener;
|
|
37
66
|
for (let i = 0; i < channel0.length; i++) {
|
|
38
67
|
const t = channel0[i];
|
|
39
68
|
const upper = t.text.toUpperCase();
|
|
@@ -41,10 +70,15 @@ function findSplitEnds(text, tokens, dialect) {
|
|
|
41
70
|
// `BEGIN TRAN`/`TRANSACTION`/`DISTRIBUTED` (T-SQL) starts a transaction, not a
|
|
42
71
|
// scripting compound — it has no matching END, so it must not open a depth level.
|
|
43
72
|
const next = channel0[i + 1];
|
|
44
|
-
if (!next || !TRAN_WORDS.has(next.text.toUpperCase()))
|
|
73
|
+
if (!next || !TRAN_WORDS.has(next.text.toUpperCase())) {
|
|
74
|
+
if (depth === 0)
|
|
75
|
+
opener = { index: i, endsBefore: ends.length };
|
|
45
76
|
depth++;
|
|
77
|
+
}
|
|
46
78
|
}
|
|
47
79
|
else if (upper === "CASE") {
|
|
80
|
+
if (depth === 0)
|
|
81
|
+
opener = { index: i, endsBefore: ends.length };
|
|
48
82
|
depth++;
|
|
49
83
|
}
|
|
50
84
|
else if (upper === "END") {
|
|
@@ -66,42 +100,46 @@ function findSplitEnds(text, tokens, dialect) {
|
|
|
66
100
|
else {
|
|
67
101
|
depth = Math.max(0, depth - 1);
|
|
68
102
|
}
|
|
69
|
-
}
|
|
70
|
-
else if (t.text === ";") {
|
|
71
103
|
if (depth === 0)
|
|
72
|
-
|
|
104
|
+
opener = undefined;
|
|
73
105
|
}
|
|
74
|
-
else if (
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
106
|
+
else if (depth === 0) {
|
|
107
|
+
const sep = separatorAt(text, channel0, i, dialect);
|
|
108
|
+
if (sep)
|
|
109
|
+
ends.push(sep);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (depth > 0 && opener) {
|
|
113
|
+
// Unclosed level: keep the split points before it, then split at every separator from it on.
|
|
114
|
+
ends = ends.slice(0, opener.endsBefore);
|
|
115
|
+
for (let i = opener.index; i < channel0.length; i++) {
|
|
116
|
+
const sep = separatorAt(text, channel0, i, dialect);
|
|
117
|
+
if (sep)
|
|
118
|
+
ends.push(sep);
|
|
84
119
|
}
|
|
85
120
|
}
|
|
86
121
|
// Tokens are in source order, so the last channel-0 token decides whether anything real follows
|
|
87
122
|
// the last separator.
|
|
88
123
|
const lastReal = channel0[channel0.length - 1];
|
|
89
|
-
|
|
124
|
+
const last = ends[ends.length - 1];
|
|
125
|
+
if (last && (lastReal === undefined || lastReal.start < last.end)) {
|
|
90
126
|
ends.pop();
|
|
91
|
-
|
|
127
|
+
return { ends, tail: last.separator };
|
|
128
|
+
}
|
|
129
|
+
return { ends };
|
|
92
130
|
}
|
|
93
|
-
/** Turn ascending split
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
function buildCells(splitEnds, length) {
|
|
131
|
+
/** Turn ascending split points into contiguous cells tiling `[0, text.length)`. A doc with no
|
|
132
|
+
* split points is one cell; text after the last split point is the final cell, carrying `tail`
|
|
133
|
+
* (its own separator, when it is a terminated statement whose trailing trivia was folded in). */
|
|
134
|
+
function buildCells(splitEnds, tail, length) {
|
|
97
135
|
const spans = [];
|
|
98
136
|
let start = 0;
|
|
99
|
-
for (const
|
|
100
|
-
spans.push({ start, end });
|
|
101
|
-
start = end;
|
|
137
|
+
for (const e of splitEnds) {
|
|
138
|
+
spans.push({ start, end: e.end, separator: e.separator });
|
|
139
|
+
start = e.end;
|
|
102
140
|
}
|
|
103
141
|
if (start < length || spans.length === 0)
|
|
104
|
-
spans.push({ start, end: length });
|
|
142
|
+
spans.push(tail ? { start, end: length, separator: tail } : { start, end: length });
|
|
105
143
|
return spans;
|
|
106
144
|
}
|
|
107
145
|
/** The tiling invariant: contiguous, starts at 0, ends at `length`, in order. */
|
|
@@ -123,14 +161,16 @@ function tiles(spans, length) {
|
|
|
123
161
|
* Total: never throws. Splits at channel-0 `;` at compound depth 0 (BEGIN/CASE
|
|
124
162
|
* increment, END decrements, floor 0; a T-SQL `BEGIN TRAN`/`TRANSACTION`/
|
|
125
163
|
* `DISTRIBUTED` does not open a depth level) plus, for T-SQL, a `GO` batch
|
|
126
|
-
* separator alone on its line
|
|
164
|
+
* separator alone on its line; text ending inside an open level splits at every
|
|
165
|
+
* separator from the unclosed opener on (see `findSplitEnds`). Each cell carries
|
|
166
|
+
* the separator token that ends it. Returns the whole doc as one cell when
|
|
127
167
|
* splitting is unsafe (the tiling invariant fails) or pointless (no separators).
|
|
128
168
|
*/
|
|
129
169
|
export function splitStatements(text, dialect) {
|
|
130
170
|
try {
|
|
131
171
|
const tokens = tokenize(text, dialect);
|
|
132
|
-
const
|
|
133
|
-
const spans = buildCells(
|
|
172
|
+
const { ends, tail } = findSplitEnds(text, tokens, dialect);
|
|
173
|
+
const spans = buildCells(ends, tail, text.length);
|
|
134
174
|
return tiles(spans, text.length) ? spans : wholeDoc(text);
|
|
135
175
|
}
|
|
136
176
|
catch (e) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { parse, analyze, toAst, toScopes, qualify, lineage, deriveSymbols, TypeInfo, type Nullability, Lineage, originsOfExpr, lineageAt, lineageOf, type LineageHop, type ViaStep, tokenize, SqlDocument, LineIndex, complete, completeAt, type Completion, type CompletionResult, type ReplaceRange, type CompleteOptions, type CandidateIdentity, type CandidateDecoration, type DecorateCandidate, jinjaSlotAt, type JinjaSlot, signatureAt, SIGNATURES, lookupSignature, hasSignature, renderSignature, FN_DOCS, lookupFnDoc, referencesAt, type Occurrence, type Occurrences, frameAt, type Frame, clausesOf, type ClauseInfo, type ClauseKind, setOpArmsOf, type SetOpArm, type SetOpArms, dialectSymbols, type DialectSymbols, dialectVocabulary, type DialectVocabulary, reservedKeywords, type KeywordEntry, type KeywordReservation, CallbackSchema, type SchemaProvider, type TableResolver, DERIVED_DIALECTS, resolveDialect, foldIdentifier, displayName, type IdentKind, type SignatureHelpInfo, type SignatureLabel, type FnSignature, type ParamSig, type RenderSignatureOptions, type FnDoc, type Dialect, type DialectOpts, type ParseResultIR, type Analysis, type Token, type TokenRole, type DocumentAnalysis, type StatementCell, type StatementCellSpan, type DocumentVariant, type UnionCte, } from "./api.js";
|
|
1
|
+
export { parse, analyze, toAst, toScopes, qualify, lineage, deriveSymbols, TypeInfo, type Nullability, Lineage, originsOfExpr, lineageAt, lineageOf, type LineageHop, type ViaStep, tokenize, SqlDocument, LineIndex, complete, completeAt, type Completion, type CompletionResult, type ReplaceRange, type CompleteOptions, type CandidateIdentity, type CandidateDecoration, type DecorateCandidate, jinjaSlotAt, type JinjaSlot, signatureAt, SIGNATURES, lookupSignature, hasSignature, renderSignature, FN_DOCS, lookupFnDoc, referencesAt, type Occurrence, type Occurrences, frameAt, type Frame, clausesOf, type ClauseInfo, type ClauseKind, setOpArmsOf, type SetOpArm, type SetOpArms, dialectSymbols, type DialectSymbols, dialectVocabulary, type DialectVocabulary, reservedKeywords, type KeywordEntry, type KeywordReservation, CallbackSchema, type SchemaProvider, type TableResolver, DERIVED_DIALECTS, resolveDialect, foldIdentifier, displayName, type IdentKind, type SignatureHelpInfo, type SignatureLabel, type FnSignature, type ParamSig, type RenderSignatureOptions, type FnDoc, type Dialect, type DialectOpts, type ParseResultIR, type Analysis, type Token, type TokenRole, type DocumentAnalysis, type StatementCell, type StatementCellSpan, statementSpans, type DocumentVariant, type UnionCte, } from "./api.js";
|
|
2
2
|
export { SqlSession, type SessionOptions } from "./session.js";
|
|
3
3
|
export { parseDatabricks } from "./databricks/parse.js";
|
|
4
4
|
export { parseTSql } from "./tsql/parse.js";
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// - Building blocks: the per-dialect parse*/lower and the raw shared passes, for callers who
|
|
11
11
|
// want a specific tier or the raw CST escape hatch.
|
|
12
12
|
// --- Uniform entry, lift helpers, typed wrappers, composable passes (src/api.ts) ---
|
|
13
|
-
export { parse, analyze, toAst, toScopes, qualify, lineage, deriveSymbols, TypeInfo, Lineage, originsOfExpr, lineageAt, lineageOf, tokenize, SqlDocument, LineIndex, complete, completeAt, jinjaSlotAt, signatureAt, SIGNATURES, lookupSignature, hasSignature, renderSignature, FN_DOCS, lookupFnDoc, referencesAt, frameAt, clausesOf, setOpArmsOf, dialectSymbols, dialectVocabulary, reservedKeywords, CallbackSchema, DERIVED_DIALECTS, resolveDialect, foldIdentifier, displayName, } from "./api.js";
|
|
13
|
+
export { parse, analyze, toAst, toScopes, qualify, lineage, deriveSymbols, TypeInfo, Lineage, originsOfExpr, lineageAt, lineageOf, tokenize, SqlDocument, LineIndex, complete, completeAt, jinjaSlotAt, signatureAt, SIGNATURES, lookupSignature, hasSignature, renderSignature, FN_DOCS, lookupFnDoc, referencesAt, frameAt, clausesOf, setOpArmsOf, dialectSymbols, dialectVocabulary, reservedKeywords, CallbackSchema, DERIVED_DIALECTS, resolveDialect, foldIdentifier, displayName, statementSpans, } from "./api.js";
|
|
14
14
|
// SqlSession — the verb-shaped facade over one SqlDocument (offset in, answer out; pure delegation).
|
|
15
15
|
export { SqlSession } from "./session.js";
|
|
16
16
|
// --- Per-dialect building blocks: parse* (CST + errors) and lower* (CST → IR), kept as one
|
package/dist/minijinja/engine.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { parseTemplated, parseTemplatedCell } from "./parse.js";
|
|
1
|
+
import { parseTemplated, parseTemplatedCell, placeholderOf } from "./parse.js";
|
|
2
2
|
import { templateVariants } from "./variants.js";
|
|
3
3
|
/** The minijinja template engine (the Rust engine dbt Fusion uses — the grammar
|
|
4
4
|
* oracle for what we accept). The shipped, and only, TemplateEngine. */
|
|
@@ -7,6 +7,7 @@ export function minijinja() {
|
|
|
7
7
|
name: "minijinja",
|
|
8
8
|
parse: (text, dialect, opts) => parseTemplated(text, dialect, opts),
|
|
9
9
|
variants: (text, dialect) => templateVariants(text, dialect),
|
|
10
|
+
placeholder: (text, _dialect, opts) => placeholderOf(text, opts),
|
|
10
11
|
parseCell: (whole, span, text, dialect, opts) => parseTemplatedCell(whole, span, text, dialect, opts),
|
|
11
12
|
};
|
|
12
13
|
}
|
|
@@ -43,3 +43,7 @@ export declare function parseTemplatedCell(whole: TemplatedParseResult, span: {
|
|
|
43
43
|
start: number;
|
|
44
44
|
end: number;
|
|
45
45
|
}, text: string, dialect: Dialect, opts?: TemplatedParseOptions): TemplatedCellResult;
|
|
46
|
+
/** The placeholder `parseTemplated` would parse for `text` (`TemplateEngine.placeholder`): the
|
|
47
|
+
* segmenter alone, no SQL parse. Total: the text itself when segmentation gives up, the same
|
|
48
|
+
* floor `parseTemplated`'s degrade path reports as its placeholder. */
|
|
49
|
+
export declare function placeholderOf(text: string, opts?: TemplatedParseOptions): string;
|
package/dist/minijinja/parse.js
CHANGED
|
@@ -675,6 +675,18 @@ export function parseTemplatedCell(whole, span, text, dialect, opts) {
|
|
|
675
675
|
})),
|
|
676
676
|
};
|
|
677
677
|
}
|
|
678
|
+
/** The placeholder `parseTemplated` would parse for `text` (`TemplateEngine.placeholder`): the
|
|
679
|
+
* segmenter alone, no SQL parse. Total: the text itself when segmentation gives up, the same
|
|
680
|
+
* floor `parseTemplated`'s degrade path reports as its placeholder. */
|
|
681
|
+
export function placeholderOf(text, opts) {
|
|
682
|
+
try {
|
|
683
|
+
return segment(text, opts?.provider ?? OPEN_PROVIDER).placeholder;
|
|
684
|
+
}
|
|
685
|
+
catch (e) {
|
|
686
|
+
debugRethrow(e);
|
|
687
|
+
return text;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
678
690
|
/** The cell start's 0-based line / column / char offset in `text` (`\n` is the line break, the
|
|
679
691
|
* convention every span in the pipeline follows; a `\r` is an ordinary column). */
|
|
680
692
|
function cellBaseOf(text, offset) {
|
|
@@ -122,6 +122,10 @@ export interface TemplateEngine {
|
|
|
122
122
|
parse(text: string, dialect: Dialect, opts?: TemplatedParseOptions): TemplatedParseResult;
|
|
123
123
|
/** Optional: coherent per-branch variant enumeration, for engines with control-flow arms. */
|
|
124
124
|
variants?(text: string, dialect: Dialect): TemplateVariant[];
|
|
125
|
+
/** Optional: the placeholder-filled SQL text `parse` would see for `text` (see
|
|
126
|
+
* `TemplatedParseResult.placeholder`), without running the SQL parse. Total: on any internal
|
|
127
|
+
* surprise answer `text` itself. Backs `statementSpans`, which only needs the split. */
|
|
128
|
+
placeholder?(text: string, dialect: Dialect, opts?: TemplatedParseOptions): string;
|
|
125
129
|
/** Optional: the products of ONE statement cell of a templated document, the plain parse of
|
|
126
130
|
* `whole.placeholder`'s slice `[span.start, span.end)` (cell-relative) with `whole`'s tags
|
|
127
131
|
* correlated onto it. `whole` is this engine's own `parse` result for the full `text`, `span`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sqllens",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"description": "A TypeScript SQL parser and static analyzer: parse, resolve names, infer types, and trace column lineage across many SQL dialects (Databricks, T-SQL, Snowflake, BigQuery, Redshift, PostgreSQL, DuckDB, Trino, SQLite, MySQL).",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|