@sqlanvil/cli 1.36.2 → 1.36.3
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 +1 -1
- package/bundle.js +136 -26
- package/package.json +1 -1
- package/._LICENSE +0 -0
- package/._NOTICE +0 -0
- package/._README.md +0 -0
- package/._bundle.js +0 -0
- package/._package.json +0 -0
- package/._worker_bundle.js +0 -0
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ authority for the version you have installed: `sqlanvil help` lists the commands
|
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
npm install -g @sqlanvil/cli
|
|
15
|
-
sqlanvil --version # sqlanvil 1.36.
|
|
15
|
+
sqlanvil --version # sqlanvil 1.36.3 (Dataform core 3.1.2)
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
Requires Node.js 20.19+ or 22.12+. `--version` reports the sqlanvil release and the Dataform core
|
package/bundle.js
CHANGED
|
@@ -55124,7 +55124,7 @@ function requireVersion () {
|
|
|
55124
55124
|
hasRequiredVersion = 1;
|
|
55125
55125
|
Object.defineProperty(version, "__esModule", { value: true });
|
|
55126
55126
|
version.dataformVersion = version.version = void 0;
|
|
55127
|
-
version.version = "1.36.
|
|
55127
|
+
version.version = "1.36.3";
|
|
55128
55128
|
version.dataformVersion = "3.1.2";
|
|
55129
55129
|
|
|
55130
55130
|
return version;
|
|
@@ -62482,6 +62482,7 @@ function requireSql_lex () {
|
|
|
62482
62482
|
hasRequiredSql_lex = 1;
|
|
62483
62483
|
Object.defineProperty(sql_lex, "__esModule", { value: true });
|
|
62484
62484
|
sql_lex.tokenize = tokenize;
|
|
62485
|
+
sql_lex.interpolationSpans = interpolationSpans;
|
|
62485
62486
|
sql_lex.significant = significant;
|
|
62486
62487
|
sql_lex.isWord = isWord;
|
|
62487
62488
|
sql_lex.matchBracket = matchBracket;
|
|
@@ -62504,16 +62505,7 @@ function requireSql_lex () {
|
|
|
62504
62505
|
}
|
|
62505
62506
|
if (ch === "$" && sql[i + 1] === "{") {
|
|
62506
62507
|
const start = i;
|
|
62507
|
-
|
|
62508
|
-
for (; i < sql.length; i++) {
|
|
62509
|
-
if (sql[i] === "{") {
|
|
62510
|
-
depth++;
|
|
62511
|
-
}
|
|
62512
|
-
else if (sql[i] === "}" && --depth === 0) {
|
|
62513
|
-
i++;
|
|
62514
|
-
break;
|
|
62515
|
-
}
|
|
62516
|
-
}
|
|
62508
|
+
i = templateEnd(sql, i);
|
|
62517
62509
|
push("template", start, i);
|
|
62518
62510
|
continue;
|
|
62519
62511
|
}
|
|
@@ -62552,6 +62544,10 @@ function requireSql_lex () {
|
|
|
62552
62544
|
const quote = sql[i];
|
|
62553
62545
|
i++;
|
|
62554
62546
|
for (; i < sql.length; i++) {
|
|
62547
|
+
if (sql[i] === "$" && sql[i + 1] === "{") {
|
|
62548
|
+
i = templateEnd(sql, i) - 1;
|
|
62549
|
+
continue;
|
|
62550
|
+
}
|
|
62555
62551
|
if (sql[i] !== quote) {
|
|
62556
62552
|
continue;
|
|
62557
62553
|
}
|
|
@@ -62598,6 +62594,36 @@ function requireSql_lex () {
|
|
|
62598
62594
|
}
|
|
62599
62595
|
return tokens;
|
|
62600
62596
|
}
|
|
62597
|
+
function templateEnd(sql, start) {
|
|
62598
|
+
let depth = 0;
|
|
62599
|
+
for (let i = start; i < sql.length; i++) {
|
|
62600
|
+
if (sql[i] === "{") {
|
|
62601
|
+
depth++;
|
|
62602
|
+
}
|
|
62603
|
+
else if (sql[i] === "}" && --depth === 0) {
|
|
62604
|
+
return i + 1;
|
|
62605
|
+
}
|
|
62606
|
+
}
|
|
62607
|
+
return sql.length;
|
|
62608
|
+
}
|
|
62609
|
+
function interpolationSpans(sql) {
|
|
62610
|
+
const spans = [];
|
|
62611
|
+
for (const t of tokenize(sql)) {
|
|
62612
|
+
if (t.kind === "template") {
|
|
62613
|
+
spans.push({ start: t.start, end: t.end });
|
|
62614
|
+
}
|
|
62615
|
+
else if (t.kind === "string" || t.kind === "quoted-ident") {
|
|
62616
|
+
for (let i = t.start; i < t.end; i++) {
|
|
62617
|
+
if (sql[i] === "$" && sql[i + 1] === "{") {
|
|
62618
|
+
const end = Math.min(templateEnd(sql, i), t.end);
|
|
62619
|
+
spans.push({ start: i, end });
|
|
62620
|
+
i = end - 1;
|
|
62621
|
+
}
|
|
62622
|
+
}
|
|
62623
|
+
}
|
|
62624
|
+
}
|
|
62625
|
+
return spans;
|
|
62626
|
+
}
|
|
62601
62627
|
function significant(tokens) {
|
|
62602
62628
|
return tokens.filter((t) => t.kind !== "whitespace" && t.kind !== "comment");
|
|
62603
62629
|
}
|
|
@@ -63637,11 +63663,22 @@ ${description} columnTypes: {
|
|
|
63637
63663
|
rewrite: (args) => (args.length === 1 ? `extract(epoch from ${args[0]})::bigint` : null),
|
|
63638
63664
|
},
|
|
63639
63665
|
];
|
|
63666
|
+
function callRuleView(text, isRewritableOffset) {
|
|
63667
|
+
const chars = Array.from(text, (c, i) => (c === "\n" || isRewritableOffset(i) ? c : " "));
|
|
63668
|
+
for (const t of (0, sql_lex_1.tokenize)(chars.join(""))) {
|
|
63669
|
+
if (t.kind === "quoted-ident" && !t.text.includes("\n")) {
|
|
63670
|
+
for (let i = t.start + 1; i < t.end - 1; i++) {
|
|
63671
|
+
chars[i] = " ";
|
|
63672
|
+
}
|
|
63673
|
+
}
|
|
63674
|
+
}
|
|
63675
|
+
return chars.join("");
|
|
63676
|
+
}
|
|
63640
63677
|
function applyCallRules(text, isRewritableOffset) {
|
|
63641
63678
|
const applied = [];
|
|
63642
63679
|
let result = text;
|
|
63643
63680
|
for (let pass = 0; pass < 10; pass++) {
|
|
63644
|
-
const mask = maskSql(result);
|
|
63681
|
+
const mask = maskSql(callRuleView(result, isRewritableOffset));
|
|
63645
63682
|
const sites = [];
|
|
63646
63683
|
for (const rule of CALL_RULES) {
|
|
63647
63684
|
const finder = new RegExp(`\\b${rule.name}\\s*\\(`, "gi");
|
|
@@ -63704,9 +63741,65 @@ ${description} columnTypes: {
|
|
|
63704
63741
|
}
|
|
63705
63742
|
return -1;
|
|
63706
63743
|
}
|
|
63707
|
-
function
|
|
63744
|
+
function blankSpans(text, spans) {
|
|
63745
|
+
if (spans.length === 0) {
|
|
63746
|
+
return text;
|
|
63747
|
+
}
|
|
63748
|
+
return Array.from(text, (c, i) => c !== "\n" && spans.some((s) => i >= s.start && i < s.end) ? " " : c).join("");
|
|
63749
|
+
}
|
|
63750
|
+
const DQ_STRING_NOTE = "BigQuery \"string\" → 'string' (double quotes are identifiers in PostgreSQL)";
|
|
63751
|
+
const TRIPLE_QUOTED_NOTE = 'BigQuery """string""" → $sa$string$sa$ (PostgreSQL has no triple-quoted strings)';
|
|
63752
|
+
function convertDoubleQuotedStrings(text, isSqlOffset, note) {
|
|
63753
|
+
const chars = Array.from(text, (c, i) => (c === "\n" || isSqlOffset(i) ? c : " "));
|
|
63754
|
+
const edits = [];
|
|
63755
|
+
const triple = /"""[\s\S]*?"""/g;
|
|
63756
|
+
let m;
|
|
63757
|
+
while ((m = triple.exec(chars.join(""))) !== null) {
|
|
63758
|
+
const inner = text.slice(m.index + 3, m.index + m[0].length - 3);
|
|
63759
|
+
let tag = "$sa$";
|
|
63760
|
+
for (let n = 1; inner.includes(tag); n++) {
|
|
63761
|
+
tag = `$sa${n}$`;
|
|
63762
|
+
}
|
|
63763
|
+
edits.push({ start: m.index, end: m.index + m[0].length, out: `${tag}${inner}${tag}` });
|
|
63764
|
+
for (let i = m.index; i < m.index + m[0].length; i++) {
|
|
63765
|
+
chars[i] = chars[i] === "\n" ? "\n" : " ";
|
|
63766
|
+
}
|
|
63767
|
+
triple.lastIndex = m.index + m[0].length;
|
|
63768
|
+
}
|
|
63769
|
+
const toks = (0, sql_lex_1.significant)((0, sql_lex_1.tokenize)(chars.join("")));
|
|
63770
|
+
toks.forEach((t, k) => {
|
|
63771
|
+
if (t.kind !== "quoted-ident" || t.text.length < 2 || !t.text.endsWith('"')) {
|
|
63772
|
+
return;
|
|
63773
|
+
}
|
|
63774
|
+
if (t.text.includes("\n")) {
|
|
63775
|
+
return;
|
|
63776
|
+
}
|
|
63777
|
+
if ((0, sql_lex_1.isWord)(toks[k - 1], "as")) {
|
|
63778
|
+
return;
|
|
63779
|
+
}
|
|
63780
|
+
let inner = "";
|
|
63781
|
+
for (let i = t.start + 1; i < t.end - 1; i++) {
|
|
63782
|
+
if (text[i] === "\\" && text[i + 1] === "'" && isSqlOffset(i)) {
|
|
63783
|
+
inner += "''";
|
|
63784
|
+
i++;
|
|
63785
|
+
}
|
|
63786
|
+
else {
|
|
63787
|
+
inner += text[i] === "'" && isSqlOffset(i) ? "''" : text[i];
|
|
63788
|
+
}
|
|
63789
|
+
}
|
|
63790
|
+
edits.push({ start: t.start, end: t.end, out: `'${inner}'` });
|
|
63791
|
+
});
|
|
63792
|
+
let out = text;
|
|
63793
|
+
for (const e of edits.sort((a, b) => b.start - a.start)) {
|
|
63794
|
+
note(e.start, e.out.startsWith("$") ? TRIPLE_QUOTED_NOTE : DQ_STRING_NOTE);
|
|
63795
|
+
out = out.slice(0, e.start) + e.out + out.slice(e.end);
|
|
63796
|
+
}
|
|
63797
|
+
return out;
|
|
63798
|
+
}
|
|
63799
|
+
function applyTextRules(text, sqlOffsetsOf, applied) {
|
|
63708
63800
|
const note = (offset, n) => applied.push({ line: text.slice(0, offset).split("\n").length, note: n });
|
|
63709
63801
|
const rewrite = (src, mask, pattern, replace, ruleNote) => {
|
|
63802
|
+
const isSqlOffset = sqlOffsetsOf(src);
|
|
63710
63803
|
const edits = [];
|
|
63711
63804
|
let m;
|
|
63712
63805
|
pattern.lastIndex = 0;
|
|
@@ -63729,18 +63822,13 @@ ${description} columnTypes: {
|
|
|
63729
63822
|
let result = text;
|
|
63730
63823
|
result = rewrite(result, maskSql(result, true), /(?<![\w"'])#[^\n]*/g, (m) => `--${m[0].slice(1)}`, "# line comment → -- (PostgreSQL has no # comment)");
|
|
63731
63824
|
result = rewrite(result, maskSql(result, true), /(?<![A-Za-z0-9_])[rR](?=['"])/g, () => "", "r'…' raw string → '…' (no raw-string prefix in PostgreSQL)");
|
|
63732
|
-
result =
|
|
63733
|
-
if (m[1]) {
|
|
63734
|
-
return null;
|
|
63735
|
-
}
|
|
63736
|
-
return m[2].includes("${") || m[2].includes("'") ? null : `'${m[2]}'`;
|
|
63737
|
-
}, "BigQuery \"string\" → 'string' (double quotes are identifiers in PostgreSQL)");
|
|
63825
|
+
result = convertDoubleQuotedStrings(result, sqlOffsetsOf(result), note);
|
|
63738
63826
|
result = rewrite(result, maskSql(result), /`([^`\n]+)`/g, (m) => (m[1].includes(".") || m[1].includes("${") ? null : `"${m[1]}"`), '`identifier` → "identifier"');
|
|
63739
63827
|
result = rewrite(result, maskSql(result, true), /\s+collate\s+(''|"")/gi, () => "", "x COLLATE '' → x (collation stripping is a no-op in PostgreSQL)");
|
|
63740
63828
|
for (;;) {
|
|
63741
63829
|
const mask = maskSql(result);
|
|
63742
63830
|
const m = /\bextract\s*\(\s*dayofweek\s+from\s+/i.exec(mask);
|
|
63743
|
-
if (!m || !
|
|
63831
|
+
if (!m || !sqlOffsetsOf(result)(m.index)) {
|
|
63744
63832
|
break;
|
|
63745
63833
|
}
|
|
63746
63834
|
const close = matchParen(mask, mask.indexOf("(", m.index));
|
|
@@ -63752,7 +63840,7 @@ ${description} columnTypes: {
|
|
|
63752
63840
|
result =
|
|
63753
63841
|
result.slice(0, m.index) + `(extract(dow from ${inner}) + 1)` + result.slice(close + 1);
|
|
63754
63842
|
}
|
|
63755
|
-
return rewriteUnenforcedConstraints(result,
|
|
63843
|
+
return rewriteUnenforcedConstraints(result, sqlOffsetsOf(result), applied);
|
|
63756
63844
|
}
|
|
63757
63845
|
const UNENFORCED_HEADER = [
|
|
63758
63846
|
"BigQuery declared the constraint below NOT ENFORCED — advisory metadata for BI tools,",
|
|
@@ -63869,6 +63957,13 @@ ${description} columnTypes: {
|
|
|
63869
63957
|
const dialectPass = dialect === "postgres";
|
|
63870
63958
|
let span = jsMode ? null : findConfigBlock(source);
|
|
63871
63959
|
const findings = [];
|
|
63960
|
+
const configAndJsSpans = (text) => {
|
|
63961
|
+
if (jsMode) {
|
|
63962
|
+
return [{ start: 0, end: text.length }];
|
|
63963
|
+
}
|
|
63964
|
+
const config = findConfigBlock(text);
|
|
63965
|
+
return [...(config ? [{ start: config.start, end: config.end }] : []), ...jsBlockSpans(text)];
|
|
63966
|
+
};
|
|
63872
63967
|
if (dialectPass) {
|
|
63873
63968
|
const outsideConfig = (off) => {
|
|
63874
63969
|
const s = jsMode ? null : findConfigBlock(source);
|
|
@@ -63882,11 +63977,12 @@ ${description} columnTypes: {
|
|
|
63882
63977
|
findings.push({ line: a.line, kind: "rewrite", note: a.note, class: classIdFor(a.note) });
|
|
63883
63978
|
}
|
|
63884
63979
|
const textApplied = [];
|
|
63885
|
-
|
|
63886
|
-
|
|
63887
|
-
|
|
63888
|
-
!
|
|
63889
|
-
|
|
63980
|
+
source = applyTextRules(source, (text) => {
|
|
63981
|
+
const notSql = configAndJsSpans(text);
|
|
63982
|
+
const templates = (0, sql_lex_1.interpolationSpans)(blankSpans(text, notSql));
|
|
63983
|
+
return (off) => !notSql.some((s) => off >= s.start && off < s.end) &&
|
|
63984
|
+
!templates.some((t) => off >= t.start && off < t.end);
|
|
63985
|
+
}, textApplied);
|
|
63890
63986
|
for (const a of textApplied) {
|
|
63891
63987
|
findings.push({
|
|
63892
63988
|
line: a.line,
|
|
@@ -63899,6 +63995,20 @@ ${description} columnTypes: {
|
|
|
63899
63995
|
}
|
|
63900
63996
|
const lines = source.split("\n");
|
|
63901
63997
|
const jsLines = jsMode ? new Set() : jsBlockLines(source);
|
|
63998
|
+
if (!jsMode) {
|
|
63999
|
+
const sql = blankSpans(source, configAndJsSpans(source));
|
|
64000
|
+
const spans = [
|
|
64001
|
+
...(0, sql_lex_1.interpolationSpans)(sql),
|
|
64002
|
+
...(0, sql_lex_1.tokenize)(sql).filter((t) => t.kind === "string" || t.kind === "quoted-ident"),
|
|
64003
|
+
];
|
|
64004
|
+
let lineStart = 0;
|
|
64005
|
+
lines.forEach((line, i) => {
|
|
64006
|
+
if (spans.some((s) => lineStart > s.start && lineStart < s.end)) {
|
|
64007
|
+
jsLines.add(i);
|
|
64008
|
+
}
|
|
64009
|
+
lineStart += line.length + 1;
|
|
64010
|
+
});
|
|
64011
|
+
}
|
|
63902
64012
|
let configStartLine = -1;
|
|
63903
64013
|
let configEndLine = -1;
|
|
63904
64014
|
if (span) {
|
package/package.json
CHANGED
package/._LICENSE
DELETED
|
Binary file
|
package/._NOTICE
DELETED
|
Binary file
|
package/._README.md
DELETED
|
Binary file
|
package/._bundle.js
DELETED
|
Binary file
|
package/._package.json
DELETED
|
Binary file
|
package/._worker_bundle.js
DELETED
|
Binary file
|