sqllens 1.1.0 → 1.2.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 +2 -74
- package/THIRD-PARTY-NOTICES.md +50 -5
- package/dist/api.d.ts +5 -3
- package/dist/api.js +11 -4
- package/dist/bigquery/behavior.d.ts +2 -0
- package/dist/bigquery/behavior.js +20 -0
- package/dist/bigquery/dot-path.d.ts +0 -2
- package/dist/bigquery/dot-path.js +0 -1
- package/dist/bigquery/fold.d.ts +8 -0
- package/dist/bigquery/fold.js +39 -0
- package/dist/bigquery/index.d.ts +7 -0
- package/dist/bigquery/index.js +10 -0
- package/dist/{infer/bigquery.d.ts → bigquery/infer.d.ts} +2 -2
- package/dist/{infer/bigquery.js → bigquery/infer.js} +4 -3
- package/dist/bigquery/lower.js +35 -12
- package/dist/bigquery/signatures.generated.d.ts +6 -0
- package/dist/bigquery/signatures.generated.js +1068 -0
- package/dist/completion/atn-walk.d.ts +13 -2
- package/dist/completion/atn-walk.js +13 -10
- package/dist/completion/complete.d.ts +4 -3
- package/dist/completion/complete.js +101 -45
- package/dist/completion/jinja-slot.d.ts +24 -0
- package/dist/completion/jinja-slot.js +126 -0
- package/dist/completion/parser-factory.d.ts +13 -1
- package/dist/completion/parser-factory.js +12 -0
- package/dist/databricks/behavior.d.ts +2 -0
- package/dist/databricks/behavior.js +19 -0
- package/dist/databricks/fold.d.ts +8 -0
- package/dist/databricks/fold.js +27 -0
- package/dist/databricks/index.d.ts +7 -0
- package/dist/databricks/index.js +10 -0
- package/dist/databricks/infer.d.ts +6 -0
- package/dist/databricks/infer.js +638 -0
- package/dist/databricks/signatures.generated.d.ts +6 -0
- package/dist/databricks/signatures.generated.js +1745 -0
- package/dist/dialect-behavior/behavior.d.ts +26 -0
- package/dist/dialect-behavior/behavior.js +1 -0
- package/dist/dialect-behavior/carrier.d.ts +5 -0
- package/dist/dialect-behavior/carrier.js +5 -0
- package/dist/dialect-behavior/coerce-rules.d.ts +7 -0
- package/dist/dialect-behavior/coerce-rules.js +69 -0
- package/dist/dialect-behavior/public-fold.d.ts +6 -0
- package/dist/dialect-behavior/public-fold.js +9 -0
- package/dist/dialect-behavior/registry.d.ts +6 -0
- package/dist/dialect-behavior/registry.js +34 -0
- package/dist/dialect-symbols.js +16 -19
- package/dist/document/document.d.ts +1 -1
- package/dist/document/document.js +8 -7
- package/dist/duckdb/behavior.d.ts +2 -0
- package/dist/duckdb/behavior.js +21 -0
- package/dist/duckdb/fold.d.ts +8 -0
- package/dist/duckdb/fold.js +29 -0
- package/dist/duckdb/index.d.ts +7 -0
- package/dist/duckdb/index.js +10 -0
- package/dist/{infer/duckdb.d.ts → duckdb/infer.d.ts} +2 -2
- package/dist/{infer/duckdb.js → duckdb/infer.js} +4 -3
- package/dist/duckdb/lower.js +47 -15
- package/dist/duckdb/signatures.generated.d.ts +6 -0
- package/dist/duckdb/signatures.generated.js +1072 -0
- package/dist/generated/bigquery/GoogleSQLParser.js +0 -7060
- package/dist/generated/databricks/DatabricksParser.js +0 -4800
- package/dist/generated/duckdb/DuckdbParser.js +0 -9100
- package/dist/generated/minijinja/MinijinjaParser.js +0 -380
- package/dist/generated/mysql/MysqlParser.js +0 -6330
- package/dist/generated/postgres/PostgresParser.js +0 -8530
- package/dist/generated/redshift/RedshiftParser.js +0 -10970
- package/dist/generated/snowflake/SnowflakeParser.js +0 -7320
- package/dist/generated/sqlite/SqliteParser.js +0 -1150
- package/dist/generated/trino/TrinoParser.js +0 -3770
- package/dist/generated/tsql/TSqlParser.js +0 -8420
- package/dist/ident/fold.d.ts +24 -15
- package/dist/ident/fold.js +12 -194
- package/dist/index.d.ts +2 -2
- package/dist/index.js +10 -8
- package/dist/infer/functions.d.ts +22 -11
- package/dist/infer/functions.js +26 -888
- package/dist/infer/infer.js +16 -14
- package/dist/infer/nullability.js +3 -4
- package/dist/infer/types.d.ts +1 -1
- package/dist/infer/types.js +7 -7
- package/dist/ir/ir.d.ts +26 -17
- package/dist/ir/span.js +0 -2
- package/dist/ir/walk.js +3 -3
- package/dist/lineage/hops.js +13 -10
- package/dist/lineage/lineage.js +10 -7
- package/dist/minijinja/apply-tags.d.ts +14 -7
- package/dist/minijinja/apply-tags.js +66 -121
- package/dist/minijinja/parse.js +5 -5
- package/dist/minijinja/tag-ast.d.ts +29 -36
- package/dist/minijinja/tag-ast.js +210 -90
- package/dist/mysql/behavior.d.ts +2 -0
- package/dist/mysql/behavior.js +21 -0
- package/dist/mysql/fold.d.ts +8 -0
- package/dist/mysql/fold.js +49 -0
- package/dist/mysql/index.d.ts +7 -0
- package/dist/mysql/index.js +10 -0
- package/dist/{infer/mysql.d.ts → mysql/infer.d.ts} +2 -2
- package/dist/{infer/mysql.js → mysql/infer.js} +3 -2
- package/dist/mysql/signatures.generated.d.ts +6 -0
- package/dist/mysql/signatures.generated.js +508 -0
- package/dist/postgres/behavior.d.ts +2 -0
- package/dist/postgres/behavior.js +19 -0
- package/dist/postgres/fold.d.ts +8 -0
- package/dist/postgres/fold.js +30 -0
- package/dist/postgres/index.d.ts +7 -0
- package/dist/postgres/index.js +10 -0
- package/dist/{infer/postgres.d.ts → postgres/infer.d.ts} +2 -2
- package/dist/{infer/postgres.js → postgres/infer.js} +4 -3
- package/dist/postgres/lower.js +2 -2
- package/dist/postgres/signatures.generated.d.ts +6 -0
- package/dist/postgres/signatures.generated.js +2973 -0
- package/dist/qualify/check-calls.js +80 -161
- package/dist/qualify/qualify.js +16 -14
- package/dist/qualify/schema-provider.js +2 -2
- package/dist/qualify/schema.js +3 -3
- package/dist/qualify/template-provider.d.ts +45 -12
- package/dist/qualify/template-provider.js +69 -38
- package/dist/redshift/behavior.d.ts +2 -0
- package/dist/redshift/behavior.js +19 -0
- package/dist/redshift/fold.d.ts +8 -0
- package/dist/redshift/fold.js +31 -0
- package/dist/redshift/index.d.ts +7 -0
- package/dist/redshift/index.js +10 -0
- package/dist/{infer/redshift.d.ts → redshift/infer.d.ts} +2 -2
- package/dist/{infer/redshift.js → redshift/infer.js} +4 -3
- package/dist/redshift/lower.js +2 -2
- package/dist/redshift/signatures.generated.d.ts +6 -0
- package/dist/redshift/signatures.generated.js +757 -0
- package/dist/references/references.js +17 -12
- package/dist/scope/like-pattern.d.ts +2 -0
- package/dist/scope/like-pattern.js +15 -0
- package/dist/scope/scope.d.ts +5 -5
- package/dist/scope/scope.js +48 -42
- package/dist/sema/resolve.js +17 -12
- package/dist/session.d.ts +2 -2
- package/dist/signature/signature.d.ts +14 -6
- package/dist/signature/signature.js +30 -22
- package/dist/signature/signatures.d.ts +14 -12
- package/dist/signature/signatures.js +42 -721
- package/dist/snowflake/behavior.d.ts +2 -0
- package/dist/snowflake/behavior.js +22 -0
- package/dist/snowflake/fold.d.ts +8 -0
- package/dist/snowflake/fold.js +25 -0
- package/dist/snowflake/index.d.ts +7 -0
- package/dist/snowflake/index.js +10 -0
- package/dist/{infer/snowflake.d.ts → snowflake/infer.d.ts} +2 -2
- package/dist/{infer/snowflake.js → snowflake/infer.js} +4 -3
- package/dist/snowflake/lower.js +59 -19
- package/dist/snowflake/signatures.generated.d.ts +6 -0
- package/dist/snowflake/signatures.generated.js +2080 -0
- package/dist/sqlite/behavior.d.ts +2 -0
- package/dist/sqlite/behavior.js +19 -0
- package/dist/sqlite/fold.d.ts +8 -0
- package/dist/sqlite/fold.js +41 -0
- package/dist/sqlite/index.d.ts +7 -0
- package/dist/sqlite/index.js +10 -0
- package/dist/{infer/sqlite.d.ts → sqlite/infer.d.ts} +2 -2
- package/dist/{infer/sqlite.js → sqlite/infer.js} +4 -3
- package/dist/sqlite/signatures.generated.d.ts +6 -0
- package/dist/sqlite/signatures.generated.js +277 -0
- package/dist/symbols/symbols.js +14 -12
- package/dist/trino/behavior.d.ts +2 -0
- package/dist/trino/behavior.js +21 -0
- package/dist/trino/fold.d.ts +8 -0
- package/dist/trino/fold.js +39 -0
- package/dist/trino/index.d.ts +7 -0
- package/dist/trino/index.js +10 -0
- package/dist/{infer/trino.d.ts → trino/infer.d.ts} +2 -2
- package/dist/{infer/trino.js → trino/infer.js} +4 -3
- package/dist/trino/lower.js +5 -5
- package/dist/trino/signatures.generated.d.ts +6 -0
- package/dist/trino/signatures.generated.js +968 -0
- package/dist/tsql/behavior.d.ts +2 -0
- package/dist/tsql/behavior.js +20 -0
- package/dist/tsql/fold.d.ts +8 -0
- package/dist/tsql/fold.js +34 -0
- package/dist/tsql/index.d.ts +7 -0
- package/dist/tsql/index.js +10 -0
- package/dist/tsql/infer.d.ts +16 -0
- package/dist/tsql/infer.js +289 -0
- package/dist/tsql/lower.js +4 -4
- package/dist/tsql/signatures.generated.d.ts +6 -0
- package/dist/tsql/signatures.generated.js +640 -0
- package/package.json +5 -10
- package/dist/generated/bigquery/GoogleSQLLexer.d.ts +0 -407
- package/dist/generated/bigquery/GoogleSQLParser.d.ts +0 -9558
- package/dist/generated/bigquery/GoogleSQLParserListener.d.ts +0 -7777
- package/dist/generated/bigquery/GoogleSQLParserListener.js +0 -7070
- package/dist/generated/databricks/DatabricksLexer.d.ts +0 -566
- package/dist/generated/databricks/DatabricksParser.d.ts +0 -7771
- package/dist/generated/databricks/DatabricksParserListener.d.ts +0 -5737
- package/dist/generated/databricks/DatabricksParserListener.js +0 -5256
- package/dist/generated/duckdb/DuckdbLexer.d.ts +0 -691
- package/dist/generated/duckdb/DuckdbParser.d.ts +0 -13932
- package/dist/generated/duckdb/DuckdbParserListener.d.ts +0 -10049
- package/dist/generated/duckdb/DuckdbParserListener.js +0 -9138
- package/dist/generated/minijinja/MinijinjaLexer.d.ts +0 -108
- package/dist/generated/minijinja/MinijinjaParser.d.ts +0 -604
- package/dist/generated/minijinja/MinijinjaParserListener.d.ts +0 -449
- package/dist/generated/minijinja/MinijinjaParserListener.js +0 -410
- package/dist/generated/mysql/MysqlLexer.d.ts +0 -1198
- package/dist/generated/mysql/MysqlParser.d.ts +0 -10992
- package/dist/generated/mysql/MysqlParserListener.d.ts +0 -7592
- package/dist/generated/mysql/MysqlParserListener.js +0 -6958
- package/dist/generated/postgres/PostgresLexer.d.ts +0 -663
- package/dist/generated/postgres/PostgresParser.d.ts +0 -12963
- package/dist/generated/postgres/PostgresParserListener.d.ts +0 -9408
- package/dist/generated/postgres/PostgresParserListener.js +0 -8554
- package/dist/generated/redshift/RedshiftLexer.d.ts +0 -954
- package/dist/generated/redshift/RedshiftParser.d.ts +0 -16939
- package/dist/generated/redshift/RedshiftParserListener.d.ts +0 -12092
- package/dist/generated/redshift/RedshiftParserListener.js +0 -10994
- package/dist/generated/snowflake/SnowflakeLexer.d.ts +0 -1046
- package/dist/generated/snowflake/SnowflakeParser.d.ts +0 -14196
- package/dist/generated/snowflake/SnowflakeParserListener.d.ts +0 -8063
- package/dist/generated/snowflake/SnowflakeParserListener.js +0 -7330
- package/dist/generated/sqlite/SqliteLexer.d.ts +0 -210
- package/dist/generated/sqlite/SqliteParser.d.ts +0 -2115
- package/dist/generated/sqlite/SqliteParserListener.d.ts +0 -1276
- package/dist/generated/sqlite/SqliteParserListener.js +0 -1160
- package/dist/generated/trino/TrinoLexer.d.ts +0 -381
- package/dist/generated/trino/TrinoParser.d.ts +0 -5340
- package/dist/generated/trino/TrinoParserListener.d.ts +0 -4704
- package/dist/generated/trino/TrinoParserListener.js +0 -4326
- package/dist/generated/tsql/TSqlLexer.d.ts +0 -1278
- package/dist/generated/tsql/TSqlParser.d.ts +0 -17267
- package/dist/generated/tsql/TSqlParserListener.d.ts +0 -9697
- package/dist/generated/tsql/TSqlParserListener.js +0 -8854
- package/dist/infer/dialect.d.ts +0 -21
- package/dist/infer/dialect.js +0 -100
- package/dist/infer/literals.d.ts +0 -6
- package/dist/infer/literals.js +0 -44
- package/dist/signature/generated/tsql.d.ts +0 -3
- package/dist/signature/generated/tsql.js +0 -260
|
@@ -1,32 +1,29 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
|
-
// R3
|
|
2
|
+
// R3: a templated call in a FROM slot as a first-class TableSource node (inc2).
|
|
3
3
|
//
|
|
4
|
-
// `{{ ref('x') }}` / `{{ source('a','b') }}` in a FROM/JOIN slot lowers, via the
|
|
5
|
-
// placeholder mechanism, to an ordinary `TableSource` whose `name` is the raw
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
// so the whole downstream pipeline works UNCHANGED).
|
|
4
|
+
// `{{ ref('x') }}` / `{{ source('a','b') }}` / a macro call in a FROM/JOIN slot lowers, via the
|
|
5
|
+
// placeholder mechanism, to an ordinary `TableSource` whose `name` is the raw placeholder identifier
|
|
6
|
+
// (PLACEHOLDER_CHAR-filled runs like `jjj…` from segment.ts). This POST-LOWER transform rewrites those
|
|
7
|
+
// sources so `name` carries the provider-resolved relation name and attaches a `template` marker, so
|
|
8
|
+
// scope/qualify/lineage see the relation, not the placeholder (scope binds a TableSource purely by
|
|
9
|
+
// `name`, so the whole downstream pipeline works UNCHANGED).
|
|
11
10
|
//
|
|
12
|
-
// Correlation is by CONTAINMENT, not equality: a `TableSource` correlates with a
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
// the first line, but its offset still sits inside the whole-tag span.
|
|
11
|
+
// Correlation is by CONTAINMENT, not equality: a `TableSource` correlates with a tag when the char
|
|
12
|
+
// offset of its FIRST NAME TOKEN (`cst.start.start`) lies inside the tag's `tagSpan` [start, end).
|
|
13
|
+
// Containment (not equality) because a multi-line expr tag fills ONE placeholder identifier per line,
|
|
14
|
+
// so the name token covers only the first line but its offset still sits inside the whole-tag span.
|
|
17
15
|
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
16
|
+
// The tag AST is NEUTRAL (a call is a call), and so is the naming: this transform asks the
|
|
17
|
+
// TemplateProvider for a call's relation (`provider.relationOf`) and carries no ref/source vocabulary
|
|
18
|
+
// itself. The NEUTRAL provider answers nothing, so a bare parse leaves calls opaque; a
|
|
19
|
+
// DbtTemplateProvider names ref/source. Naming is never-wrong: a resolved name comes from the call's
|
|
20
|
+
// literal args, and a call whose relation the provider does not resolve keeps its placeholder name and
|
|
21
|
+
// stays opaque. We NEVER fabricate a name.
|
|
24
22
|
//
|
|
25
|
-
// The IR is frozen after lower(); this transform REBUILDS with STRUCTURAL SHARING
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
// `ast` unchanged.
|
|
23
|
+
// The IR is frozen after lower(); this transform REBUILDS with STRUCTURAL SHARING (new objects only on
|
|
24
|
+
// changed paths, an unchanged subtree keeps its original already-frozen reference) and re-freezes the
|
|
25
|
+
// rebuilt tree. It NEVER mutates a frozen node. Total: never throws, on any internal surprise it
|
|
26
|
+
// returns the input `ast` unchanged.
|
|
30
27
|
// ---------------------------------------------------------------------------
|
|
31
28
|
import { freezeIR } from "../ir/freeze.js";
|
|
32
29
|
/** Record a freshly built node's correlation to the tag it came from, then return it unchanged
|
|
@@ -43,27 +40,23 @@ function attach(ctx, node, tag) {
|
|
|
43
40
|
return node;
|
|
44
41
|
}
|
|
45
42
|
/**
|
|
46
|
-
* Rewrite templated FROM/JOIN sources in `ast` to carry their
|
|
47
|
-
* a `template` marker, correlating each source to a tag by span
|
|
48
|
-
* Returns the SAME `ast` reference when nothing correlates (structural sharing);
|
|
49
|
-
* returns a re-frozen rebuilt tree otherwise. Total
|
|
50
|
-
*
|
|
43
|
+
* Rewrite templated FROM/JOIN sources in `ast` to carry their provider-resolved name (when the
|
|
44
|
+
* provider resolves the call) plus a `template` marker, correlating each source to a tag by span
|
|
45
|
+
* containment. Returns the SAME `ast` reference when nothing correlates (structural sharing);
|
|
46
|
+
* returns a re-frozen rebuilt tree otherwise. Total, never throws; the correlation maps are empty
|
|
47
|
+
* (not absent) on the no-op and error paths.
|
|
51
48
|
*/
|
|
52
|
-
export function applyTemplateTags(ast, tags, text) {
|
|
49
|
+
export function applyTemplateTags(ast, tags, text, provider) {
|
|
53
50
|
const byNode = new WeakMap();
|
|
54
51
|
const byTag = new Map();
|
|
55
52
|
try {
|
|
56
|
-
// config is a no-output tag (whitespace-filled)
|
|
57
|
-
// source
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
t.kind === "macro" ||
|
|
61
|
-
t.kind === "var" ||
|
|
62
|
-
t.kind === "env_var" ||
|
|
63
|
-
t.kind === "other");
|
|
53
|
+
// config is a no-output tag (whitespace-filled), so it can never yield a table
|
|
54
|
+
// source and stays out of the correlation set even though ExprTag admits it.
|
|
55
|
+
// An incomplete/mid-typing call (`{{ ref('cu`) is NOT a resolved source, so skip it.
|
|
56
|
+
const relTags = tags.filter((t) => (t.kind === "call" && !t.incomplete) || t.kind === "other");
|
|
64
57
|
if (relTags.length === 0)
|
|
65
58
|
return { ast, byNode, byTag };
|
|
66
|
-
const ctx = { relTags, sets: resolveSets(tags, text), text, byNode, byTag };
|
|
59
|
+
const ctx = { relTags, sets: resolveSets(tags, text, provider), text, provider, byNode, byTag };
|
|
67
60
|
const next = transformQuery(ast, ctx);
|
|
68
61
|
// Scalar-slot marking: every column-shaped node whose token is a tag's placeholder
|
|
69
62
|
// fill gets a `template` marker (span + provider key), so inference resolves it
|
|
@@ -79,23 +72,12 @@ export function applyTemplateTags(ast, tags, text) {
|
|
|
79
72
|
* its provider key — ref/source from their literal names, macro from its call fields,
|
|
80
73
|
* var/env_var lexically, a bare set-bound variable from its RHS call. */
|
|
81
74
|
function exprInfoOf(tag, ctx) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (tag.kind === "
|
|
85
|
-
return { span: tag.tagSpan, call: { name: "source", args: [tag.sourceName, tag.tableName] } };
|
|
86
|
-
}
|
|
87
|
-
if (tag.kind === "macro")
|
|
75
|
+
// A call tag (ref/source/var/env_var/a macro) carries its provider key straight off the call,
|
|
76
|
+
// callOf reads name + literal args from the source, uniform across every callee.
|
|
77
|
+
if (tag.kind === "call")
|
|
88
78
|
return { span: tag.tagSpan, call: callOf(tag, ctx.text) };
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (m) {
|
|
92
|
-
const args = [m[3]];
|
|
93
|
-
if (m[4] !== undefined)
|
|
94
|
-
args.push(null); // further args present but not extracted — computed
|
|
95
|
-
return { span: tag.tagSpan, call: { name: m[1], args } };
|
|
96
|
-
}
|
|
97
|
-
return { span: tag.tagSpan };
|
|
98
|
-
}
|
|
79
|
+
// A non-call `other` tag: a bare `{{ t }}` resolving through a single-call `{% set t = … %}`
|
|
80
|
+
// carries that RHS call; anything else is opaque.
|
|
99
81
|
const ident = bareIdentOf(tag, ctx.text);
|
|
100
82
|
const resolved = ident !== undefined ? ctx.sets.get(ident) : undefined;
|
|
101
83
|
if (resolved)
|
|
@@ -175,14 +157,6 @@ const LITERAL_ARG = /^(['"])([^'"\\]*)\1$/;
|
|
|
175
157
|
function sliceSpan(text, span) {
|
|
176
158
|
return text.slice(span.start, span.end);
|
|
177
159
|
}
|
|
178
|
-
/** The literal string value of a MacroCall argument, or undefined when computed. */
|
|
179
|
-
function literalArg(text, call, i) {
|
|
180
|
-
const arg = call.args[i];
|
|
181
|
-
if (!arg)
|
|
182
|
-
return undefined;
|
|
183
|
-
const m = LITERAL_ARG.exec(sliceSpan(text, arg.span).trim());
|
|
184
|
-
return m ? m[2] : undefined;
|
|
185
|
-
}
|
|
186
160
|
/** A kwarg's raw text split: `name = rest`, with `rest`'s literal (or null when computed). */
|
|
187
161
|
const KWARG_RE = /^([A-Za-z_][A-Za-z0-9_]*)\s*=(?!=)([\s\S]*)$/;
|
|
188
162
|
/**
|
|
@@ -190,7 +164,7 @@ const KWARG_RE = /^([A-Za-z_][A-Za-z0-9_]*)\s*=(?!=)([\s\S]*)$/;
|
|
|
190
164
|
* carried separately (the channel-agreed TemplateCall contract: quote-stripped, escapes
|
|
191
165
|
* NOT resolved, computed arguments null, kwargs never dropped).
|
|
192
166
|
*/
|
|
193
|
-
function callOf(mc, text) {
|
|
167
|
+
export function callOf(mc, text) {
|
|
194
168
|
const args = [];
|
|
195
169
|
const kwargs = [];
|
|
196
170
|
for (const arg of mc.args) {
|
|
@@ -217,11 +191,11 @@ function callOf(mc, text) {
|
|
|
217
191
|
* Requires the tag's call list to be exactly one call that IS the ENTIRE RHS: the
|
|
218
192
|
* text between the declared name and the call is exactly `=`, and the text after
|
|
219
193
|
* the call runs straight to the tag close (whitespace + optional `-%}`).
|
|
220
|
-
* `ref('a') ~ '_x'` or `ref('a').identifier` therefore do not resolve.
|
|
221
|
-
*
|
|
222
|
-
*
|
|
194
|
+
* `ref('a') ~ '_x'` or `ref('a').identifier` therefore do not resolve. When the provider resolves the
|
|
195
|
+
* call's relation, the set carries that NAME (scope binds the real relation); otherwise it carries the
|
|
196
|
+
* call identity only, and the provider may still resolve its relation at the use site.
|
|
223
197
|
*/
|
|
224
|
-
function setResolution(tag, text) {
|
|
198
|
+
function setResolution(tag, text, provider) {
|
|
225
199
|
if (tag.calls.length !== 1 || !tag.nameSpan)
|
|
226
200
|
return undefined;
|
|
227
201
|
const call = tag.calls[0];
|
|
@@ -234,19 +208,11 @@ function setResolution(tag, text) {
|
|
|
234
208
|
if (!/^\s*-?%\}$/.test(text.slice(callEnd, tag.tagSpan.end)))
|
|
235
209
|
return undefined;
|
|
236
210
|
const tCall = callOf(call, text);
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
return model !== undefined ? { kind: "ref", name: [model], call: tCall } : undefined;
|
|
240
|
-
}
|
|
241
|
-
if (call.packageName === undefined && call.name === "source" && call.args.length === 2) {
|
|
242
|
-
const src = literalArg(text, call, 0);
|
|
243
|
-
const tbl = literalArg(text, call, 1);
|
|
244
|
-
return src !== undefined && tbl !== undefined ? { kind: "source", name: [src, tbl], call: tCall } : undefined;
|
|
245
|
-
}
|
|
246
|
-
return { kind: "macro", call: tCall };
|
|
211
|
+
const rel = provider.relationOf(tCall);
|
|
212
|
+
return rel ? { name: [...rel.nameParts], call: tCall } : { call: tCall };
|
|
247
213
|
}
|
|
248
214
|
/** The template-wide map of resolvable set variables (empty when any guard trips globally). */
|
|
249
|
-
function resolveSets(tags, text) {
|
|
215
|
+
function resolveSets(tags, text, provider) {
|
|
250
216
|
const empty = new Map();
|
|
251
217
|
const controls = tags.filter((t) => t.kind === "control");
|
|
252
218
|
if (controls.some((c) => c.keyword === "macro"))
|
|
@@ -258,7 +224,7 @@ function resolveSets(tags, text) {
|
|
|
258
224
|
if (c.keyword !== "set" || !c.name)
|
|
259
225
|
continue;
|
|
260
226
|
counts.set(c.name, (counts.get(c.name) ?? 0) + 1);
|
|
261
|
-
const r = setResolution(c, text);
|
|
227
|
+
const r = setResolution(c, text, provider);
|
|
262
228
|
if (r)
|
|
263
229
|
out.set(c.name, r);
|
|
264
230
|
}
|
|
@@ -433,51 +399,30 @@ function transformTableSource(src, ctx) {
|
|
|
433
399
|
const aliasTok = src.aliasCst?.start;
|
|
434
400
|
const base = aliasTok != null && inSpan(aliasTok.start, tag.tagSpan) ? withoutAlias(src) : src;
|
|
435
401
|
// NOTE: `template.span` intentionally aliases `tag.tagSpan` BY REFERENCE. freezeIR
|
|
436
|
-
// therefore also freezes the TagNode.tagSpan object returned in `.tags
|
|
437
|
-
// since spans are read-only. Every marker
|
|
438
|
-
//
|
|
439
|
-
if (tag.kind === "
|
|
440
|
-
const call =
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
const
|
|
447
|
-
|
|
402
|
+
// therefore also freezes the TagNode.tagSpan object returned in `.tags`, benign
|
|
403
|
+
// since spans are read-only. Every call marker carries its `call`, the provider key
|
|
404
|
+
// the semantic layer resolves the relation and its columns through (relation-columns.ts).
|
|
405
|
+
if (tag.kind === "call") {
|
|
406
|
+
const call = callOf(tag, ctx.text);
|
|
407
|
+
const rel = ctx.provider.relationOf(call);
|
|
408
|
+
// A call in a FROM slot (ref/source/a TVF-like macro). When the provider resolves its
|
|
409
|
+
// relation, carry the resolved name; otherwise keep the placeholder name (never fabricated).
|
|
410
|
+
// Either way the `call` keeps it consultable, so an unresolved call is not a dead end: a
|
|
411
|
+
// provider added later resolves it. ref vs source is not stored here, it is call.name.
|
|
412
|
+
const named = rel ? { ...base, name: [...rel.nameParts] } : base;
|
|
413
|
+
const template = { kind: "call", span: tag.tagSpan, call };
|
|
414
|
+
return attach(ctx, { ...named, template }, tag);
|
|
448
415
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
// opaque marker (exemption, no diagnostics).
|
|
454
|
-
const template = { kind: "macro", span: tag.tagSpan, call: callOf(tag, ctx.text) };
|
|
455
|
-
return attach(ctx, { ...base, template }, tag);
|
|
456
|
-
}
|
|
457
|
-
// Non-call expression tag (var / env_var / other) in a FROM slot. A bare `{{ t }}`
|
|
458
|
-
// resolving through a `{% set t = … %}` single-call RHS binds the real model
|
|
459
|
-
// (ref/source) or carries the call identity (macro); everything else gets the opaque
|
|
460
|
-
// "expr" marker — either way the placeholder name stops posing as a real table.
|
|
416
|
+
// Non-call expression tag (var / env_var / other) in a FROM slot. A bare `{{ t }}` resolving
|
|
417
|
+
// through a `{% set t = … %}` single-call RHS carries the resolved relation name (when the
|
|
418
|
+
// provider resolved it) or the call identity alone; every other case gets the opaque "expr"
|
|
419
|
+
// marker, so the placeholder name stops posing as a real table.
|
|
461
420
|
const ident = tag.kind === "other" ? bareIdentOf(tag, ctx.text) : undefined;
|
|
462
421
|
const resolved = ident !== undefined ? ctx.sets.get(ident) : undefined;
|
|
463
|
-
if (resolved && resolved.kind !== "macro") {
|
|
464
|
-
const template = {
|
|
465
|
-
kind: resolved.kind,
|
|
466
|
-
span: tag.tagSpan,
|
|
467
|
-
indirect: true,
|
|
468
|
-
call: resolved.call,
|
|
469
|
-
};
|
|
470
|
-
return attach(ctx, { ...base, name: [...resolved.name], template }, tag);
|
|
471
|
-
}
|
|
472
422
|
if (resolved) {
|
|
473
|
-
|
|
474
|
-
const template = {
|
|
475
|
-
|
|
476
|
-
span: tag.tagSpan,
|
|
477
|
-
indirect: true,
|
|
478
|
-
call: resolved.call,
|
|
479
|
-
};
|
|
480
|
-
return attach(ctx, { ...base, template }, tag);
|
|
423
|
+
const named = resolved.name ? { ...base, name: [...resolved.name] } : base;
|
|
424
|
+
const template = { kind: "call", span: tag.tagSpan, indirect: true, call: resolved.call };
|
|
425
|
+
return attach(ctx, { ...named, template }, tag);
|
|
481
426
|
}
|
|
482
427
|
const template = { kind: "expr", span: tag.tagSpan, opaque: true };
|
|
483
428
|
return attach(ctx, { ...base, template }, tag);
|
package/dist/minijinja/parse.js
CHANGED
|
@@ -282,7 +282,7 @@ function build(text, dialect, provider) {
|
|
|
282
282
|
jinjaTokens.push(mapSliceToken(tok));
|
|
283
283
|
}
|
|
284
284
|
const { tree, diagnostics } = parseSliceTag(slice);
|
|
285
|
-
const tag = tagNodesOf(seg, tree);
|
|
285
|
+
const tag = tagNodesOf(seg, tree, slice);
|
|
286
286
|
if (tag) {
|
|
287
287
|
tags.push(tag);
|
|
288
288
|
segToTag.set(seg, tag);
|
|
@@ -292,12 +292,12 @@ function build(text, dialect, provider) {
|
|
|
292
292
|
jinjaDiagnostics.push(...diagnostics);
|
|
293
293
|
}
|
|
294
294
|
// Step 5b (R3): rewrite templated FROM/JOIN sources onto first-class TableSource
|
|
295
|
-
// nodes carrying the
|
|
296
|
-
// scope/qualify/lineage bind the real
|
|
295
|
+
// nodes carrying the provider-resolved relation name and a `template` marker, so
|
|
296
|
+
// scope/qualify/lineage bind the real relation rather than the `jjj…` placeholder.
|
|
297
297
|
// Total (returns the input ast on any surprise); the reassignment stays inside
|
|
298
298
|
// build()'s caller try/catch so parseTemplated's totality holds. `correlation`
|
|
299
|
-
// carries the Task 10 tag
|
|
300
|
-
const correlation = applyTemplateTags(sql.ast, tags, text);
|
|
299
|
+
// carries the Task 10 tag to IR-node join collected while rebuilding.
|
|
300
|
+
const correlation = applyTemplateTags(sql.ast, tags, text, provider);
|
|
301
301
|
const sqlResult = { ...sql, ast: correlation.ast };
|
|
302
302
|
// Step 4c: merge into one source-ordered stream. SQL and jinja token spans are
|
|
303
303
|
// disjoint (tag-contained SQL tokens were dropped), so a stable sort by start
|
|
@@ -1,14 +1,27 @@
|
|
|
1
|
-
import { ParserRuleContext } from "antlr4ng";
|
|
2
|
-
import { CallExprContext } from "../generated/minijinja/MinijinjaParser.js";
|
|
1
|
+
import { ParserRuleContext, Token as AntlrToken } from "antlr4ng";
|
|
3
2
|
import type { PartSpan } from "../ir/part-span.js";
|
|
4
3
|
import { type Segment } from "./segment.js";
|
|
5
4
|
/** A tag segment (the `kind: "tag"` arm of Segment). */
|
|
6
5
|
type TagSegment = Extract<Segment, {
|
|
7
6
|
kind: "tag";
|
|
8
7
|
}>;
|
|
8
|
+
/**
|
|
9
|
+
* One argument of a call, in the same spirit as a SQL function-call's args. `span` is the WHOLE
|
|
10
|
+
* argument (quote-included: `'orders'`, or `model='orders'` for a kwarg). `value` is the literal
|
|
11
|
+
* value quote-stripped (`orders`), or `null` for a computed arg (`ref(var('x'))`, `'a' ~ b`), never
|
|
12
|
+
* fabricated. `valueSpan` is the quote-EXCLUDED span of that literal value (covers `orders`, not
|
|
13
|
+
* `'orders'`), present only when there's a literal value. So a consumer that knows a call's arg roles
|
|
14
|
+
* (e.g. dbt: `ref`'s model is the last arg) reads the value + valueSpan straight off here, exactly
|
|
15
|
+
* how the old `ref.model`/`modelSpan` read.
|
|
16
|
+
*/
|
|
17
|
+
export interface TagArg {
|
|
18
|
+
value: string | null;
|
|
19
|
+
span: PartSpan;
|
|
20
|
+
valueSpan?: PartSpan;
|
|
21
|
+
}
|
|
9
22
|
/**
|
|
10
23
|
* The reusable call fields the extension consumes for signature-help / hover — the
|
|
11
|
-
*
|
|
24
|
+
* call TagNode's fields minus `kind`/`tagSpan`. A `{{ }}` call node IS a
|
|
12
25
|
* MacroCall + kind/tagSpan; a `{% %}` control tag carries an array of them
|
|
13
26
|
* (`calls`). Every field comes only from real identifier tokens (never-wrong): a
|
|
14
27
|
* computed / dynamic callee yields no MacroCall.
|
|
@@ -19,9 +32,7 @@ export interface MacroCall {
|
|
|
19
32
|
packageName?: string;
|
|
20
33
|
packageSpan?: PartSpan;
|
|
21
34
|
argsSpan?: PartSpan;
|
|
22
|
-
args:
|
|
23
|
-
span: PartSpan;
|
|
24
|
-
}[];
|
|
35
|
+
args: TagArg[];
|
|
25
36
|
}
|
|
26
37
|
/**
|
|
27
38
|
* R2 tag-AST node. The ref/source/macro arms carry the span contract the
|
|
@@ -30,31 +41,16 @@ export interface MacroCall {
|
|
|
30
41
|
* 0-based offsets — sqllens convention).
|
|
31
42
|
*/
|
|
32
43
|
export type TagNode = {
|
|
33
|
-
kind: "
|
|
34
|
-
model: string;
|
|
35
|
-
modelSpan: PartSpan;
|
|
36
|
-
callSpan: PartSpan;
|
|
37
|
-
tagSpan: PartSpan;
|
|
38
|
-
} | {
|
|
39
|
-
kind: "source";
|
|
40
|
-
sourceName: string;
|
|
41
|
-
tableName: string;
|
|
42
|
-
sourceNameSpan: PartSpan;
|
|
43
|
-
tableNameSpan: PartSpan;
|
|
44
|
-
/** Span of the whole `source(…)` call — the sibling of `ref`'s `callSpan`; the extension hit-tests the bare `source` identifier / call on it. */
|
|
45
|
-
callSpan: PartSpan;
|
|
46
|
-
tagSpan: PartSpan;
|
|
47
|
-
} | {
|
|
48
|
-
kind: "macro";
|
|
44
|
+
kind: "call";
|
|
49
45
|
name: string;
|
|
50
46
|
nameSpan: PartSpan;
|
|
51
47
|
packageName?: string;
|
|
52
48
|
packageSpan?: PartSpan;
|
|
49
|
+
/** The whole call `name(args)` (name/package through the close paren). */
|
|
50
|
+
callSpan: PartSpan;
|
|
53
51
|
tagSpan: PartSpan;
|
|
54
52
|
argsSpan?: PartSpan;
|
|
55
|
-
args:
|
|
56
|
-
span: PartSpan;
|
|
57
|
-
}[];
|
|
53
|
+
args: TagArg[];
|
|
58
54
|
/**
|
|
59
55
|
* Every macro CALL in the expression, in source order, EACH as its own
|
|
60
56
|
* MacroCall — symmetric to `control.calls` (C1). A NESTED `outer(inner())`
|
|
@@ -66,6 +62,12 @@ export type TagNode = {
|
|
|
66
62
|
* uniformly for control AND macro nodes.
|
|
67
63
|
*/
|
|
68
64
|
calls: MacroCall[];
|
|
65
|
+
/** Present (true) when the call is UNCLOSED / mid-typing (`{{ ref('cu`) and was recovered
|
|
66
|
+
* from the raw tokens because the parser could not build a complete call node. Its args are
|
|
67
|
+
* best-effort (a partial string arg has `value: null`); a consumer knows not to treat it as
|
|
68
|
+
* a confirmed reference, and completion uses it to place the caret's arg slot. Absent on a
|
|
69
|
+
* normally-parsed (closed) call. */
|
|
70
|
+
incomplete?: true;
|
|
69
71
|
} | {
|
|
70
72
|
kind: "control";
|
|
71
73
|
tagSpan: PartSpan;
|
|
@@ -85,18 +87,9 @@ export type TagNode = {
|
|
|
85
87
|
*/
|
|
86
88
|
calls: MacroCall[];
|
|
87
89
|
} | {
|
|
88
|
-
kind: "
|
|
90
|
+
kind: "other";
|
|
89
91
|
tagSpan: PartSpan;
|
|
90
92
|
};
|
|
91
|
-
/**
|
|
92
|
-
* Extract a CallExprContext into the reusable MacroCall fields — name/nameSpan +
|
|
93
|
-
* optional package via `decomposeCallee`, args[] + argsSpan via `argInfo`. Returns
|
|
94
|
-
* undefined when the callee is not a real, locatable identifier (decomposeCallee
|
|
95
|
-
* undefined, or no nameSpan): a computed / dynamic callee is skipped, never
|
|
96
|
-
* fabricated (never-wrong). The `{{ }}` macro node and the `{% %}` control tag both
|
|
97
|
-
* build from this, so a call surfaces identically wherever it appears.
|
|
98
|
-
*/
|
|
99
|
-
export declare function callToMacroCall(call: CallExprContext): MacroCall | undefined;
|
|
100
93
|
/**
|
|
101
94
|
* Build the R2 tag-AST node for ONE tag. `seg` carries the tag's document range
|
|
102
95
|
* (`seg.start`/`seg.end`, used for `tagSpan`'s offsets — its own line/column come
|
|
@@ -105,5 +98,5 @@ export declare function callToMacroCall(call: CallExprContext): MacroCall | unde
|
|
|
105
98
|
* offset/anchor composition anywhere in this file). Returns undefined only for an
|
|
106
99
|
* empty/degenerate tree (never throws).
|
|
107
100
|
*/
|
|
108
|
-
export declare function tagNodesOf(seg: TagSegment, tree: ParserRuleContext): TagNode | undefined;
|
|
101
|
+
export declare function tagNodesOf(seg: TagSegment, tree: ParserRuleContext, tokens?: readonly AntlrToken[]): TagNode | undefined;
|
|
109
102
|
export {};
|