@adep/cli 0.1.9 → 0.1.10

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 (3) hide show
  1. package/dist/index.js +346 -62
  2. package/dist/vite.js +323 -47
  3. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -1687,6 +1687,7 @@ function stripQuotes(raw) {
1687
1687
  const t = raw.trim();
1688
1688
  if (/^'.*'$/.test(t)) return t.slice(1, -1);
1689
1689
  if (/^".*"$/.test(t)) return t.slice(1, -1);
1690
+ if (/^NULL$/i.test(t)) return null;
1690
1691
  return t;
1691
1692
  }
1692
1693
  function parseCreateTable(ddl) {
@@ -1707,50 +1708,109 @@ function parseCreateTable(ddl) {
1707
1708
  }
1708
1709
  return { name, columns };
1709
1710
  }
1710
- function parseWhereClauses(whereRaw, cursor) {
1711
- const clauses = [];
1712
- for (const part of whereRaw.split(/\s+AND\s+/i)) {
1713
- const t = part.trim();
1714
- if (t.length === 0) continue;
1715
- if (/\bIS\s+NULL\b/i.test(t)) {
1716
- const col2 = ident(t.split(/\s+IS\s+NULL\b/i)[0] ?? "");
1717
- clauses.push({ column: col2, operator: "IS NULL", value: null, list: false });
1718
- continue;
1719
- }
1720
- if (/\bIS\s+NOT\s+NULL\b/i.test(t)) {
1721
- const col2 = ident(t.split(/\s+IS\s+NOT\s+NULL\b/i)[0] ?? "");
1722
- clauses.push({ column: col2, operator: "IS NOT NULL", value: null, list: false });
1723
- continue;
1724
- }
1725
- const opMatch = /^\s*((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_]*))\s*(=|!=|>=|<=|>|<|like|in|not\s+in)\s*(.+)$/i.exec(
1726
- t
1727
- );
1728
- if (opMatch === null) continue;
1729
- const col = ident(opMatch[1] ?? "");
1730
- const op = (opMatch[3] ?? opMatch[2] ?? "").toLowerCase();
1731
- const rhs = (opMatch[4] ?? "").trim();
1732
- if (op === "in" || op === "not in") {
1733
- const inner = rhs.replace(/^\(|\)$/g, "");
1734
- const items = splitListItems(inner);
1735
- const list = items.map((item) => {
1736
- if (item.trim() === "?") return cursor.take();
1737
- return stripQuotes(item);
1738
- });
1739
- clauses.push({ column: col, operator: op, value: list, list: true });
1711
+ function splitTopLevel2(raw, token) {
1712
+ const parts = [];
1713
+ let depth = 0;
1714
+ let inQuote = false;
1715
+ let buffer = "";
1716
+ const n = raw.length;
1717
+ const isTokenAt = (i) => {
1718
+ const word = raw.slice(i, i + token.length);
1719
+ if (word.toUpperCase() !== token) return false;
1720
+ const before = i === 0 ? "" : raw[i - 1] ?? "";
1721
+ const after = raw[i + token.length] ?? "";
1722
+ return !/[A-Za-z0-9_.]/.test(before) && !/[A-Za-z0-9_.]/.test(after);
1723
+ };
1724
+ for (let i = 0; i < n; i += 1) {
1725
+ const ch = raw[i] ?? "";
1726
+ if (ch === "'") {
1727
+ if (inQuote && raw[i + 1] === "'") {
1728
+ buffer += ch + (raw[i + 1] ?? "");
1729
+ i += 1;
1730
+ continue;
1731
+ }
1732
+ inQuote = !inQuote;
1733
+ buffer += ch;
1740
1734
  continue;
1741
1735
  }
1742
- let value;
1743
- if (rhs === "?") {
1744
- value = cursor.take();
1736
+ if (!inQuote && ch === "(") depth += 1;
1737
+ else if (!inQuote && ch === ")") depth -= 1;
1738
+ if (!inQuote && depth === 0 && isTokenAt(i)) {
1739
+ parts.push(buffer);
1740
+ buffer = "";
1741
+ i += token.length - 1;
1745
1742
  } else {
1746
- value = stripQuotes(rhs);
1743
+ buffer += ch;
1747
1744
  }
1748
- clauses.push({ column: col, operator: op, value, list: false });
1749
1745
  }
1750
- return clauses;
1746
+ parts.push(buffer);
1747
+ return parts;
1751
1748
  }
1752
- function matchWhere(clauses, row) {
1753
- return clauses.every((c) => matchValue(row[c.column], c));
1749
+ function unqualifyColumn(raw) {
1750
+ const t = raw.trim();
1751
+ const dot = t.lastIndexOf(".");
1752
+ if (dot > 0 && /^[A-Za-z_][A-Za-z0-9_]*\./.test(t)) return t.slice(dot + 1);
1753
+ return t;
1754
+ }
1755
+ function parseLeftJoins(tail) {
1756
+ const joins = [];
1757
+ const re = /LEFT\s+JOIN\s+((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_]*))\s+([A-Za-z_][A-Za-z0-9_]*)\s+ON\s+([A-Za-z_][A-Za-z0-9_.]*)\s*=\s*([A-Za-z_][A-Za-z0-9_.]*)/gi;
1758
+ let m;
1759
+ while ((m = re.exec(tail)) !== null) {
1760
+ joins.push({
1761
+ table: ident(m[1] ?? ""),
1762
+ alias: m[3] ?? "",
1763
+ leftCol: unqualifyColumn(m[4] ?? ""),
1764
+ rightCol: unqualifyColumn(m[5] ?? "")
1765
+ });
1766
+ }
1767
+ return joins;
1768
+ }
1769
+ function parseWhereClauses(whereRaw, cursor) {
1770
+ const parseAndGroup = (andRaw) => {
1771
+ const clauses = [];
1772
+ for (const part of splitTopLevel2(andRaw, "AND")) {
1773
+ const t = part.trim();
1774
+ if (t.length === 0) continue;
1775
+ if (/\bIS\s+NULL\b/i.test(t)) {
1776
+ clauses.push({ column: unqualifyColumn(ident(t.split(/\s+IS\s+NULL\b/i)[0] ?? "")), operator: "IS NULL", value: null, list: false });
1777
+ continue;
1778
+ }
1779
+ if (/\bIS\s+NOT\s+NULL\b/i.test(t)) {
1780
+ clauses.push({ column: unqualifyColumn(ident(t.split(/\s+IS\s+NOT\s+NULL\b/i)[0] ?? "")), operator: "IS NOT NULL", value: null, list: false });
1781
+ continue;
1782
+ }
1783
+ const opMatch = /^\s*((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_.]*))\s*(=|!=|>=|<=|>|<|like|in|not\s+in)\s*(.+)$/i.exec(
1784
+ t
1785
+ );
1786
+ if (opMatch === null) continue;
1787
+ const col = unqualifyColumn(ident(opMatch[1] ?? ""));
1788
+ const op = (opMatch[3] ?? opMatch[2] ?? "").toLowerCase();
1789
+ const rhs = (opMatch[4] ?? "").trim();
1790
+ if (op === "in" || op === "not in") {
1791
+ const inner = rhs.replace(/^\(|\)$/g, "");
1792
+ const items = splitListItems(inner);
1793
+ const list = items.map((item) => {
1794
+ if (item.trim() === "?") return cursor.take();
1795
+ return stripQuotes(item);
1796
+ });
1797
+ clauses.push({ column: col, operator: op, value: list, list: true });
1798
+ continue;
1799
+ }
1800
+ let value;
1801
+ if (rhs === "?") {
1802
+ value = cursor.take();
1803
+ } else {
1804
+ value = stripQuotes(rhs);
1805
+ }
1806
+ clauses.push({ column: col, operator: op, value, list: false });
1807
+ }
1808
+ return clauses;
1809
+ };
1810
+ return splitTopLevel2(whereRaw, "OR").map((group) => group.trim()).filter((group) => group.length > 0).map(parseAndGroup);
1811
+ }
1812
+ function matchWhere(groups, row) {
1813
+ return groups.some((clauses) => clauses.every((c) => matchValue(row[c.column], c)));
1754
1814
  }
1755
1815
  function splitListItems(inner) {
1756
1816
  const items = [];
@@ -1770,6 +1830,153 @@ function splitListItems(inner) {
1770
1830
  items.push(buffer);
1771
1831
  return items;
1772
1832
  }
1833
+ function resolveSetValue(value, existing, row) {
1834
+ if (value instanceof ExcludedRef) return row[value.column];
1835
+ if (value instanceof ColumnRef) return existing[value.column];
1836
+ if (value instanceof ExprRef) return evalArithmetic(value.source, existing, row);
1837
+ return value;
1838
+ }
1839
+ function evalArithmetic(src, existing, row) {
1840
+ const num = (v) => {
1841
+ const n2 = Number(v);
1842
+ return Number.isFinite(n2) ? n2 : 0;
1843
+ };
1844
+ let i = 0;
1845
+ const n = src.length;
1846
+ const skip = () => {
1847
+ while (i < n && /\s/.test(src[i] ?? "")) i += 1;
1848
+ };
1849
+ const peek = () => {
1850
+ skip();
1851
+ return i < n ? src[i] ?? "" : null;
1852
+ };
1853
+ const parseIdent = () => {
1854
+ skip();
1855
+ const m = /^([A-Za-z_][A-Za-z0-9_]*)/.exec(src.slice(i));
1856
+ if (m === null) return null;
1857
+ i += (m[1] ?? "").length;
1858
+ skip();
1859
+ let col = ident(m[1] ?? "");
1860
+ let excluded = false;
1861
+ if (src[i] === ".") {
1862
+ const m2 = /^\.([A-Za-z_][A-Za-z0-9_]*)/.exec(src.slice(i));
1863
+ if (m2 !== null) {
1864
+ i += (m2[0] ?? "").length;
1865
+ if (col.toLowerCase() === "excluded") excluded = true;
1866
+ col = ident(m2[1] ?? "");
1867
+ }
1868
+ }
1869
+ return { col, excluded };
1870
+ };
1871
+ const parseFactor = () => {
1872
+ const ch = peek();
1873
+ if (ch === "(") {
1874
+ i += 1;
1875
+ const v = parseExpr();
1876
+ skip();
1877
+ if (src[i] === ")") i += 1;
1878
+ return v;
1879
+ }
1880
+ const numMatch = /^(\d+(?:\.\d+)?)/.exec(src.slice(i));
1881
+ if (numMatch !== null) {
1882
+ i += (numMatch[1] ?? "").length;
1883
+ return Number(numMatch[1]);
1884
+ }
1885
+ const id = parseIdent();
1886
+ if (id !== null) {
1887
+ const v = id.excluded ? row[id.col] : existing[id.col];
1888
+ return num(v);
1889
+ }
1890
+ return 0;
1891
+ };
1892
+ const parseTerm = () => {
1893
+ let v = parseFactor();
1894
+ for (; ; ) {
1895
+ const ch = peek();
1896
+ if (ch !== "*" && ch !== "/") return v;
1897
+ i += 1;
1898
+ const rhs = parseFactor();
1899
+ v = ch === "*" ? v * rhs : rhs === 0 ? v : v / rhs;
1900
+ }
1901
+ };
1902
+ const parseExpr = () => {
1903
+ let v = parseTerm();
1904
+ for (; ; ) {
1905
+ const ch = peek();
1906
+ if (ch !== "+" && ch !== "-") return v;
1907
+ i += 1;
1908
+ const rhs = parseTerm();
1909
+ v = ch === "+" ? v + rhs : v - rhs;
1910
+ }
1911
+ };
1912
+ return parseExpr();
1913
+ }
1914
+ function splitInsertTuples(body) {
1915
+ const tuples = [];
1916
+ let i = 0;
1917
+ const n = body.length;
1918
+ while (i < n) {
1919
+ while (i < n && (body[i] === " " || body[i] === " " || body[i] === "\n" || body[i] === "\r" || body[i] === ",")) {
1920
+ i += 1;
1921
+ }
1922
+ if (i >= n) break;
1923
+ if (body[i] !== "(") {
1924
+ return { tuples, conflict: body.slice(i).trim() };
1925
+ }
1926
+ let depth = 0;
1927
+ let j = i;
1928
+ for (; j < n; j += 1) {
1929
+ if (body[j] === "(") depth += 1;
1930
+ else if (body[j] === ")") {
1931
+ depth -= 1;
1932
+ if (depth === 0) break;
1933
+ }
1934
+ }
1935
+ if (j >= n) return { tuples, conflict: null };
1936
+ tuples.push(body.slice(i + 1, j));
1937
+ i = j + 1;
1938
+ }
1939
+ return { tuples, conflict: null };
1940
+ }
1941
+ function parseConflictClause(clause, cursor, fallbackCols) {
1942
+ const m = /^ON\s+CONFLICT(?:\s*\(([^)]*)\))?\s+DO\s+(UPDATE\s+SET\s+([\s\S]+)|NOTHING\s*)$/i.exec(
1943
+ clause.trim()
1944
+ );
1945
+ if (m === null) {
1946
+ throw new SimDbError("DB_UNSAFE_OP", `\u65E0\u6CD5\u89E3\u6790 ON CONFLICT \u5B50\u53E5\uFF1A${clause.trim().slice(0, 60)}\u2026`);
1947
+ }
1948
+ const colsRaw = m[1];
1949
+ const cols = colsRaw === void 0 ? fallbackCols : colsRaw.split(",").map(ident);
1950
+ if (cols.length === 0) throw new SimDbError("DB_UNSAFE_OP", "ON CONFLICT \u51B2\u7A81\u5217\u4E3A\u7A7A");
1951
+ const action = m[2] ?? "";
1952
+ if (/^NOTHING/i.test(action)) return { cols, sets: [] };
1953
+ const setRaw = m[3] ?? "";
1954
+ const sets = splitListItems(setRaw).map((part) => {
1955
+ const eq = /^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*([\s\S]+)$/i.exec(part.trim());
1956
+ if (eq === null) {
1957
+ throw new SimDbError("DB_UNSAFE_OP", `\u65E0\u6CD5\u89E3\u6790 SET \u8D4B\u503C\uFF1A${part.trim().slice(0, 60)}\u2026`);
1958
+ }
1959
+ const col = ident(eq[1] ?? "");
1960
+ const rhs = (eq[2] ?? "").trim();
1961
+ let value;
1962
+ if (rhs === "?") {
1963
+ value = cursor.take();
1964
+ } else {
1965
+ const ex = /^excluded\.([A-Za-z_][A-Za-z0-9_]*)$/i.exec(rhs);
1966
+ if (ex !== null) {
1967
+ value = new ExcludedRef(ident(ex[1] ?? ""));
1968
+ } else if (/^([A-Za-z_][A-Za-z0-9_]*)$/.test(rhs) && !/^NULL$/i.test(rhs)) {
1969
+ value = new ColumnRef(ident(rhs));
1970
+ } else if (/^'.*'$/.test(rhs) || /^".*"$/.test(rhs) || /^NULL$/i.test(rhs)) {
1971
+ value = stripQuotes(rhs);
1972
+ } else {
1973
+ value = new ExprRef(rhs);
1974
+ }
1975
+ }
1976
+ return { col, value };
1977
+ });
1978
+ return { cols, sets };
1979
+ }
1773
1980
  function matchValue(value, clause) {
1774
1981
  const op = clause.operator;
1775
1982
  if (op === "IS NULL") return value === null || value === void 0;
@@ -1819,6 +2026,15 @@ function indexAfter(start, matches, tail) {
1819
2026
  const end = candidates.length === 0 ? -1 : Math.min(...candidates);
1820
2027
  return end === -1 ? tail.length : end;
1821
2028
  }
2029
+ function parseSelectItem(raw) {
2030
+ const t = raw.trim();
2031
+ const as = /\s+AS\s+([A-Za-z_][A-Za-z0-9_]*)$/i.exec(t);
2032
+ let name = as === null ? t : t.slice(0, as.index).trim();
2033
+ if (unqualifyColumn(name) === "*") return { name: "", qualified: "", alias: "", star: true };
2034
+ const qualified = /^[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? ident(name) : "";
2035
+ const plain = unqualifyColumn(ident(name));
2036
+ return { name: plain, qualified, alias: as === null ? plain : ident(as[1] ?? ""), star: false };
2037
+ }
1822
2038
  function project(rows, selectRaw) {
1823
2039
  if (/^count\s*\(\s*\*/i.test(selectRaw) || /^count\s*\(\s*1\)/i.test(selectRaw)) {
1824
2040
  const alias = selectRaw.match(/\bAS\s+([A-Za-z_][A-Za-z0-9_]*)/i)?.[1] ?? "n";
@@ -1829,14 +2045,25 @@ function project(rows, selectRaw) {
1829
2045
  return [{ [constMatch[2]]: Number(constMatch[1]) }];
1830
2046
  }
1831
2047
  if (selectRaw.trim() === "*") return rows;
1832
- const cols = selectRaw.split(",").map((s) => ident(s.trim()));
2048
+ const items = selectRaw.split(",").map(parseSelectItem);
2049
+ const valueOf = (row, item) => item.qualified !== "" && row[item.qualified] !== void 0 ? row[item.qualified] : row[item.name];
2050
+ if (items.some((item) => item.star)) {
2051
+ return rows.map((row) => {
2052
+ const out = { ...row };
2053
+ for (const item of items) {
2054
+ if (item.star) continue;
2055
+ out[item.alias] = valueOf(row, item);
2056
+ }
2057
+ return out;
2058
+ });
2059
+ }
1833
2060
  return rows.map((row) => {
1834
2061
  const out = {};
1835
- for (const col of cols) out[col] = row[col];
2062
+ for (const item of items) out[item.alias] = valueOf(row, item);
1836
2063
  return out;
1837
2064
  });
1838
2065
  }
1839
- var SimDbError, ParamCursor, SimSqlEngine;
2066
+ var SimDbError, ParamCursor, ExcludedRef, ColumnRef, ExprRef, SimSqlEngine;
1840
2067
  var init_sql_engine = __esm({
1841
2068
  "packages/runtime/src/sim/sql-engine.ts"() {
1842
2069
  "use strict";
@@ -1858,6 +2085,21 @@ var init_sql_engine = __esm({
1858
2085
  return v ?? null;
1859
2086
  }
1860
2087
  };
2088
+ ExcludedRef = class {
2089
+ constructor(column) {
2090
+ this.column = column;
2091
+ }
2092
+ };
2093
+ ColumnRef = class {
2094
+ constructor(column) {
2095
+ this.column = column;
2096
+ }
2097
+ };
2098
+ ExprRef = class {
2099
+ constructor(source) {
2100
+ this.source = source;
2101
+ }
2102
+ };
1861
2103
  SimSqlEngine = class {
1862
2104
  tables = {};
1863
2105
  storage;
@@ -1967,16 +2209,36 @@ var init_sql_engine = __esm({
1967
2209
  const valueBody = match[4].trim();
1968
2210
  const cursor = new ParamCursor(params);
1969
2211
  const table = this.ensureTable(tableName);
2212
+ const { tuples, conflict } = splitInsertTuples(valueBody);
2213
+ if (tuples.length === 0) throw new SimDbError("DB_UNSAFE_OP", "INSERT \u7F3A\u5C11 VALUES \u5143\u7EC4");
2214
+ const conflictSpec = conflict === null ? null : parseConflictClause(
2215
+ conflict,
2216
+ cursor,
2217
+ table.columns.filter((c) => c.primaryKey).map((c) => c.name)
2218
+ );
1970
2219
  let inserted = 0;
1971
- for (const group of splitListItems(valueBody)) {
1972
- const inner = group.trim().replace(/^\(|\)$/g, "");
1973
- const values = splitListItems(inner).map(
2220
+ for (const tuple of tuples) {
2221
+ const values = splitListItems(tuple).map(
1974
2222
  (item) => item.trim() === "?" ? cursor.take() : stripQuotes(item)
1975
2223
  );
1976
2224
  const row = {};
1977
2225
  cols.forEach((col, i) => {
1978
2226
  row[col] = values[i] ?? null;
1979
2227
  });
2228
+ if (conflictSpec !== null) {
2229
+ const existing = table.rows.find(
2230
+ (r) => conflictSpec.cols.every((c) => r[c] === row[c])
2231
+ );
2232
+ if (existing !== void 0) {
2233
+ const oldRow = { ...existing };
2234
+ for (const set of conflictSpec.sets) {
2235
+ existing[set.col] = resolveSetValue(set.value, oldRow, row);
2236
+ }
2237
+ inserted += 1;
2238
+ void this.persist();
2239
+ continue;
2240
+ }
2241
+ }
1980
2242
  this.applyAutoincrement(table, row);
1981
2243
  table.rows.push(row);
1982
2244
  inserted += 1;
@@ -2045,6 +2307,20 @@ var init_sql_engine = __esm({
2045
2307
  return project(this.catalog(), selectRaw);
2046
2308
  }
2047
2309
  const table = this.ensureTable(tableName);
2310
+ let rows = table.rows;
2311
+ const joins = parseLeftJoins(tail);
2312
+ if (joins.length > 0) {
2313
+ rows = table.rows.map((row) => {
2314
+ const merged = { ...row };
2315
+ for (const j of joins) {
2316
+ const joined = this.tables[j.table]?.rows.find((jr) => jr[j.leftCol] === merged[j.rightCol]);
2317
+ if (joined !== void 0) {
2318
+ for (const [k, v] of Object.entries(joined)) merged[`${j.alias}.${k}`] = v;
2319
+ }
2320
+ }
2321
+ return merged;
2322
+ });
2323
+ }
2048
2324
  const whereMatch = /\bWHERE\b/i.exec(tail);
2049
2325
  const orderMatch = /\bORDER\s+BY\b/i.exec(tail);
2050
2326
  const limitMatch = /\bLIMIT\b/i.exec(tail);
@@ -2053,7 +2329,6 @@ var init_sql_engine = __esm({
2053
2329
  whereMatch.index + whereMatch[0].length,
2054
2330
  indexAfter(whereMatch.index, [orderMatch, limitMatch, offsetMatch], tail)
2055
2331
  );
2056
- let rows = table.rows;
2057
2332
  if (whereRaw.trim().length > 0) {
2058
2333
  const clauses = parseWhereClauses(whereRaw, cursor);
2059
2334
  rows = rows.filter((row) => matchWhere(clauses, row));
@@ -2063,9 +2338,9 @@ var init_sql_engine = __esm({
2063
2338
  orderMatch.index + orderMatch[0].length,
2064
2339
  indexAfter(orderMatch.index, [limitMatch, offsetMatch], tail)
2065
2340
  );
2066
- const oc = /^\s*((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_]*))\s+(asc|desc)/i.exec(orderRaw);
2341
+ const oc = /^\s*((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_.]*))\s+(asc|desc)/i.exec(orderRaw);
2067
2342
  if (oc !== null) {
2068
- const col = ident(oc[1]);
2343
+ const col = unqualifyColumn(ident(oc[1]));
2069
2344
  const dir = oc[3].toLowerCase();
2070
2345
  rows = [...rows].toSorted((a, b) => {
2071
2346
  const av = a[col];
@@ -4364,6 +4639,7 @@ function createBearerUserResolver(issuer) {
4364
4639
  }
4365
4640
  async function collectFunctions(dir) {
4366
4641
  const files = {};
4642
+ const isRuntimeSource = (name) => (name.endsWith(".ts") || name.endsWith(".js")) && !name.endsWith(".d.ts") && !name.endsWith(".test.ts");
4367
4643
  const walk = async (sub, prefix) => {
4368
4644
  let entries;
4369
4645
  try {
@@ -4376,7 +4652,7 @@ async function collectFunctions(dir) {
4376
4652
  const full = join10(sub, entry.name);
4377
4653
  if (entry.isDirectory()) {
4378
4654
  await walk(full, rel);
4379
- } else if (entry.isFile() && entry.name.endsWith(".ts")) {
4655
+ } else if (entry.isFile() && isRuntimeSource(entry.name)) {
4380
4656
  files[rel] = await readFile7(full, "utf8");
4381
4657
  }
4382
4658
  }
@@ -4983,22 +5259,29 @@ function splitSqlStatements(source) {
4983
5259
  let inQuote = false;
4984
5260
  const lines = source.split("\n");
4985
5261
  for (const rawLine of lines) {
4986
- const line = rawLine.trim();
4987
- if (line.length === 0) continue;
4988
- if (line.startsWith("--")) continue;
4989
- for (let i = 0; i < line.length; i++) {
4990
- const ch = line[i];
4991
- if (ch === "'") {
4992
- if (inQuote && line[i + 1] === "'") {
4993
- buffer += ch + line[i + 1];
4994
- i++;
4995
- continue;
5262
+ const trimmed = rawLine.trim();
5263
+ if (trimmed.length === 0 || trimmed.startsWith("--")) continue;
5264
+ for (let i = 0; i < rawLine.length; i++) {
5265
+ const ch = rawLine[i];
5266
+ if (inQuote) {
5267
+ if (ch === "'") {
5268
+ if (rawLine[i + 1] === "'") {
5269
+ buffer += ch + rawLine[i + 1];
5270
+ i++;
5271
+ continue;
5272
+ }
5273
+ inQuote = false;
4996
5274
  }
4997
- inQuote = !inQuote;
4998
5275
  buffer += ch;
4999
5276
  continue;
5000
5277
  }
5001
- if (ch === ";" && !inQuote) {
5278
+ if (ch === "'") {
5279
+ inQuote = true;
5280
+ buffer += ch;
5281
+ continue;
5282
+ }
5283
+ if (ch === "-" && rawLine[i + 1] === "-") break;
5284
+ if (ch === ";") {
5002
5285
  const statement = buffer.trim();
5003
5286
  if (statement.length > 0) statements.push(statement);
5004
5287
  buffer = "";
@@ -5532,7 +5815,8 @@ async function collectShared(functionsDir) {
5532
5815
  await walk(join13(dir, entry.name));
5533
5816
  continue;
5534
5817
  }
5535
- if (!entry.name.endsWith(".ts") || entry.name.endsWith(".test.ts")) continue;
5818
+ const isRuntimeSource = (entry.name.endsWith(".ts") || entry.name.endsWith(".js")) && !entry.name.endsWith(".d.ts") && !entry.name.endsWith(".test.ts");
5819
+ if (!isRuntimeSource) continue;
5536
5820
  const full = join13(dir, entry.name);
5537
5821
  const rel = relative3(sharedDir, full).split(sep).join("/");
5538
5822
  files[`_shared/${rel}`] = await readFile11(full, "utf8");
@@ -5643,7 +5927,7 @@ var init_frontend_draft = __esm({
5643
5927
  "shared/frontend-draft.ts"() {
5644
5928
  "use strict";
5645
5929
  FRONTEND_DRAFT_FILE_PATH_PATTERN = /^[a-zA-Z0-9._][a-zA-Z0-9._/-]*$/;
5646
- FRONTEND_DRAFT_MAX_TOTAL_SOURCE_BYTES = 256 * 1024;
5930
+ FRONTEND_DRAFT_MAX_TOTAL_SOURCE_BYTES = 512 * 1024;
5647
5931
  FRONTEND_DRAFT_MAX_FILES = 100;
5648
5932
  }
5649
5933
  });
package/dist/vite.js CHANGED
@@ -1138,6 +1138,7 @@ function stripQuotes(raw) {
1138
1138
  const t = raw.trim();
1139
1139
  if (/^'.*'$/.test(t)) return t.slice(1, -1);
1140
1140
  if (/^".*"$/.test(t)) return t.slice(1, -1);
1141
+ if (/^NULL$/i.test(t)) return null;
1141
1142
  return t;
1142
1143
  }
1143
1144
  function parseCreateTable(ddl) {
@@ -1158,50 +1159,109 @@ function parseCreateTable(ddl) {
1158
1159
  }
1159
1160
  return { name, columns };
1160
1161
  }
1161
- function parseWhereClauses(whereRaw, cursor) {
1162
- const clauses = [];
1163
- for (const part of whereRaw.split(/\s+AND\s+/i)) {
1164
- const t = part.trim();
1165
- if (t.length === 0) continue;
1166
- if (/\bIS\s+NULL\b/i.test(t)) {
1167
- const col2 = ident(t.split(/\s+IS\s+NULL\b/i)[0] ?? "");
1168
- clauses.push({ column: col2, operator: "IS NULL", value: null, list: false });
1169
- continue;
1170
- }
1171
- if (/\bIS\s+NOT\s+NULL\b/i.test(t)) {
1172
- const col2 = ident(t.split(/\s+IS\s+NOT\s+NULL\b/i)[0] ?? "");
1173
- clauses.push({ column: col2, operator: "IS NOT NULL", value: null, list: false });
1174
- continue;
1175
- }
1176
- const opMatch = /^\s*((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_]*))\s*(=|!=|>=|<=|>|<|like|in|not\s+in)\s*(.+)$/i.exec(
1177
- t
1178
- );
1179
- if (opMatch === null) continue;
1180
- const col = ident(opMatch[1] ?? "");
1181
- const op = (opMatch[3] ?? opMatch[2] ?? "").toLowerCase();
1182
- const rhs = (opMatch[4] ?? "").trim();
1183
- if (op === "in" || op === "not in") {
1184
- const inner = rhs.replace(/^\(|\)$/g, "");
1185
- const items = splitListItems(inner);
1186
- const list = items.map((item) => {
1187
- if (item.trim() === "?") return cursor.take();
1188
- return stripQuotes(item);
1189
- });
1190
- clauses.push({ column: col, operator: op, value: list, list: true });
1162
+ function splitTopLevel(raw, token) {
1163
+ const parts = [];
1164
+ let depth = 0;
1165
+ let inQuote = false;
1166
+ let buffer = "";
1167
+ const n = raw.length;
1168
+ const isTokenAt = (i) => {
1169
+ const word = raw.slice(i, i + token.length);
1170
+ if (word.toUpperCase() !== token) return false;
1171
+ const before = i === 0 ? "" : raw[i - 1] ?? "";
1172
+ const after = raw[i + token.length] ?? "";
1173
+ return !/[A-Za-z0-9_.]/.test(before) && !/[A-Za-z0-9_.]/.test(after);
1174
+ };
1175
+ for (let i = 0; i < n; i += 1) {
1176
+ const ch = raw[i] ?? "";
1177
+ if (ch === "'") {
1178
+ if (inQuote && raw[i + 1] === "'") {
1179
+ buffer += ch + (raw[i + 1] ?? "");
1180
+ i += 1;
1181
+ continue;
1182
+ }
1183
+ inQuote = !inQuote;
1184
+ buffer += ch;
1191
1185
  continue;
1192
1186
  }
1193
- let value;
1194
- if (rhs === "?") {
1195
- value = cursor.take();
1187
+ if (!inQuote && ch === "(") depth += 1;
1188
+ else if (!inQuote && ch === ")") depth -= 1;
1189
+ if (!inQuote && depth === 0 && isTokenAt(i)) {
1190
+ parts.push(buffer);
1191
+ buffer = "";
1192
+ i += token.length - 1;
1196
1193
  } else {
1197
- value = stripQuotes(rhs);
1194
+ buffer += ch;
1198
1195
  }
1199
- clauses.push({ column: col, operator: op, value, list: false });
1200
1196
  }
1201
- return clauses;
1197
+ parts.push(buffer);
1198
+ return parts;
1199
+ }
1200
+ function unqualifyColumn(raw) {
1201
+ const t = raw.trim();
1202
+ const dot = t.lastIndexOf(".");
1203
+ if (dot > 0 && /^[A-Za-z_][A-Za-z0-9_]*\./.test(t)) return t.slice(dot + 1);
1204
+ return t;
1205
+ }
1206
+ function parseLeftJoins(tail) {
1207
+ const joins = [];
1208
+ const re = /LEFT\s+JOIN\s+((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_]*))\s+([A-Za-z_][A-Za-z0-9_]*)\s+ON\s+([A-Za-z_][A-Za-z0-9_.]*)\s*=\s*([A-Za-z_][A-Za-z0-9_.]*)/gi;
1209
+ let m;
1210
+ while ((m = re.exec(tail)) !== null) {
1211
+ joins.push({
1212
+ table: ident(m[1] ?? ""),
1213
+ alias: m[3] ?? "",
1214
+ leftCol: unqualifyColumn(m[4] ?? ""),
1215
+ rightCol: unqualifyColumn(m[5] ?? "")
1216
+ });
1217
+ }
1218
+ return joins;
1202
1219
  }
1203
- function matchWhere(clauses, row) {
1204
- return clauses.every((c) => matchValue(row[c.column], c));
1220
+ function parseWhereClauses(whereRaw, cursor) {
1221
+ const parseAndGroup = (andRaw) => {
1222
+ const clauses = [];
1223
+ for (const part of splitTopLevel(andRaw, "AND")) {
1224
+ const t = part.trim();
1225
+ if (t.length === 0) continue;
1226
+ if (/\bIS\s+NULL\b/i.test(t)) {
1227
+ clauses.push({ column: unqualifyColumn(ident(t.split(/\s+IS\s+NULL\b/i)[0] ?? "")), operator: "IS NULL", value: null, list: false });
1228
+ continue;
1229
+ }
1230
+ if (/\bIS\s+NOT\s+NULL\b/i.test(t)) {
1231
+ clauses.push({ column: unqualifyColumn(ident(t.split(/\s+IS\s+NOT\s+NULL\b/i)[0] ?? "")), operator: "IS NOT NULL", value: null, list: false });
1232
+ continue;
1233
+ }
1234
+ const opMatch = /^\s*((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_.]*))\s*(=|!=|>=|<=|>|<|like|in|not\s+in)\s*(.+)$/i.exec(
1235
+ t
1236
+ );
1237
+ if (opMatch === null) continue;
1238
+ const col = unqualifyColumn(ident(opMatch[1] ?? ""));
1239
+ const op = (opMatch[3] ?? opMatch[2] ?? "").toLowerCase();
1240
+ const rhs = (opMatch[4] ?? "").trim();
1241
+ if (op === "in" || op === "not in") {
1242
+ const inner = rhs.replace(/^\(|\)$/g, "");
1243
+ const items = splitListItems(inner);
1244
+ const list = items.map((item) => {
1245
+ if (item.trim() === "?") return cursor.take();
1246
+ return stripQuotes(item);
1247
+ });
1248
+ clauses.push({ column: col, operator: op, value: list, list: true });
1249
+ continue;
1250
+ }
1251
+ let value;
1252
+ if (rhs === "?") {
1253
+ value = cursor.take();
1254
+ } else {
1255
+ value = stripQuotes(rhs);
1256
+ }
1257
+ clauses.push({ column: col, operator: op, value, list: false });
1258
+ }
1259
+ return clauses;
1260
+ };
1261
+ return splitTopLevel(whereRaw, "OR").map((group) => group.trim()).filter((group) => group.length > 0).map(parseAndGroup);
1262
+ }
1263
+ function matchWhere(groups, row) {
1264
+ return groups.some((clauses) => clauses.every((c) => matchValue(row[c.column], c)));
1205
1265
  }
1206
1266
  function splitListItems(inner) {
1207
1267
  const items = [];
@@ -1221,6 +1281,168 @@ function splitListItems(inner) {
1221
1281
  items.push(buffer);
1222
1282
  return items;
1223
1283
  }
1284
+ var ExcludedRef = class {
1285
+ constructor(column) {
1286
+ this.column = column;
1287
+ }
1288
+ };
1289
+ var ColumnRef = class {
1290
+ constructor(column) {
1291
+ this.column = column;
1292
+ }
1293
+ };
1294
+ var ExprRef = class {
1295
+ constructor(source) {
1296
+ this.source = source;
1297
+ }
1298
+ };
1299
+ function resolveSetValue(value, existing, row) {
1300
+ if (value instanceof ExcludedRef) return row[value.column];
1301
+ if (value instanceof ColumnRef) return existing[value.column];
1302
+ if (value instanceof ExprRef) return evalArithmetic(value.source, existing, row);
1303
+ return value;
1304
+ }
1305
+ function evalArithmetic(src, existing, row) {
1306
+ const num = (v) => {
1307
+ const n2 = Number(v);
1308
+ return Number.isFinite(n2) ? n2 : 0;
1309
+ };
1310
+ let i = 0;
1311
+ const n = src.length;
1312
+ const skip = () => {
1313
+ while (i < n && /\s/.test(src[i] ?? "")) i += 1;
1314
+ };
1315
+ const peek = () => {
1316
+ skip();
1317
+ return i < n ? src[i] ?? "" : null;
1318
+ };
1319
+ const parseIdent = () => {
1320
+ skip();
1321
+ const m = /^([A-Za-z_][A-Za-z0-9_]*)/.exec(src.slice(i));
1322
+ if (m === null) return null;
1323
+ i += (m[1] ?? "").length;
1324
+ skip();
1325
+ let col = ident(m[1] ?? "");
1326
+ let excluded = false;
1327
+ if (src[i] === ".") {
1328
+ const m2 = /^\.([A-Za-z_][A-Za-z0-9_]*)/.exec(src.slice(i));
1329
+ if (m2 !== null) {
1330
+ i += (m2[0] ?? "").length;
1331
+ if (col.toLowerCase() === "excluded") excluded = true;
1332
+ col = ident(m2[1] ?? "");
1333
+ }
1334
+ }
1335
+ return { col, excluded };
1336
+ };
1337
+ const parseFactor = () => {
1338
+ const ch = peek();
1339
+ if (ch === "(") {
1340
+ i += 1;
1341
+ const v = parseExpr();
1342
+ skip();
1343
+ if (src[i] === ")") i += 1;
1344
+ return v;
1345
+ }
1346
+ const numMatch = /^(\d+(?:\.\d+)?)/.exec(src.slice(i));
1347
+ if (numMatch !== null) {
1348
+ i += (numMatch[1] ?? "").length;
1349
+ return Number(numMatch[1]);
1350
+ }
1351
+ const id = parseIdent();
1352
+ if (id !== null) {
1353
+ const v = id.excluded ? row[id.col] : existing[id.col];
1354
+ return num(v);
1355
+ }
1356
+ return 0;
1357
+ };
1358
+ const parseTerm = () => {
1359
+ let v = parseFactor();
1360
+ for (; ; ) {
1361
+ const ch = peek();
1362
+ if (ch !== "*" && ch !== "/") return v;
1363
+ i += 1;
1364
+ const rhs = parseFactor();
1365
+ v = ch === "*" ? v * rhs : rhs === 0 ? v : v / rhs;
1366
+ }
1367
+ };
1368
+ const parseExpr = () => {
1369
+ let v = parseTerm();
1370
+ for (; ; ) {
1371
+ const ch = peek();
1372
+ if (ch !== "+" && ch !== "-") return v;
1373
+ i += 1;
1374
+ const rhs = parseTerm();
1375
+ v = ch === "+" ? v + rhs : v - rhs;
1376
+ }
1377
+ };
1378
+ return parseExpr();
1379
+ }
1380
+ function splitInsertTuples(body) {
1381
+ const tuples = [];
1382
+ let i = 0;
1383
+ const n = body.length;
1384
+ while (i < n) {
1385
+ while (i < n && (body[i] === " " || body[i] === " " || body[i] === "\n" || body[i] === "\r" || body[i] === ",")) {
1386
+ i += 1;
1387
+ }
1388
+ if (i >= n) break;
1389
+ if (body[i] !== "(") {
1390
+ return { tuples, conflict: body.slice(i).trim() };
1391
+ }
1392
+ let depth = 0;
1393
+ let j = i;
1394
+ for (; j < n; j += 1) {
1395
+ if (body[j] === "(") depth += 1;
1396
+ else if (body[j] === ")") {
1397
+ depth -= 1;
1398
+ if (depth === 0) break;
1399
+ }
1400
+ }
1401
+ if (j >= n) return { tuples, conflict: null };
1402
+ tuples.push(body.slice(i + 1, j));
1403
+ i = j + 1;
1404
+ }
1405
+ return { tuples, conflict: null };
1406
+ }
1407
+ function parseConflictClause(clause, cursor, fallbackCols) {
1408
+ const m = /^ON\s+CONFLICT(?:\s*\(([^)]*)\))?\s+DO\s+(UPDATE\s+SET\s+([\s\S]+)|NOTHING\s*)$/i.exec(
1409
+ clause.trim()
1410
+ );
1411
+ if (m === null) {
1412
+ throw new SimDbError("DB_UNSAFE_OP", `\u65E0\u6CD5\u89E3\u6790 ON CONFLICT \u5B50\u53E5\uFF1A${clause.trim().slice(0, 60)}\u2026`);
1413
+ }
1414
+ const colsRaw = m[1];
1415
+ const cols = colsRaw === void 0 ? fallbackCols : colsRaw.split(",").map(ident);
1416
+ if (cols.length === 0) throw new SimDbError("DB_UNSAFE_OP", "ON CONFLICT \u51B2\u7A81\u5217\u4E3A\u7A7A");
1417
+ const action = m[2] ?? "";
1418
+ if (/^NOTHING/i.test(action)) return { cols, sets: [] };
1419
+ const setRaw = m[3] ?? "";
1420
+ const sets = splitListItems(setRaw).map((part) => {
1421
+ const eq = /^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*([\s\S]+)$/i.exec(part.trim());
1422
+ if (eq === null) {
1423
+ throw new SimDbError("DB_UNSAFE_OP", `\u65E0\u6CD5\u89E3\u6790 SET \u8D4B\u503C\uFF1A${part.trim().slice(0, 60)}\u2026`);
1424
+ }
1425
+ const col = ident(eq[1] ?? "");
1426
+ const rhs = (eq[2] ?? "").trim();
1427
+ let value;
1428
+ if (rhs === "?") {
1429
+ value = cursor.take();
1430
+ } else {
1431
+ const ex = /^excluded\.([A-Za-z_][A-Za-z0-9_]*)$/i.exec(rhs);
1432
+ if (ex !== null) {
1433
+ value = new ExcludedRef(ident(ex[1] ?? ""));
1434
+ } else if (/^([A-Za-z_][A-Za-z0-9_]*)$/.test(rhs) && !/^NULL$/i.test(rhs)) {
1435
+ value = new ColumnRef(ident(rhs));
1436
+ } else if (/^'.*'$/.test(rhs) || /^".*"$/.test(rhs) || /^NULL$/i.test(rhs)) {
1437
+ value = stripQuotes(rhs);
1438
+ } else {
1439
+ value = new ExprRef(rhs);
1440
+ }
1441
+ }
1442
+ return { col, value };
1443
+ });
1444
+ return { cols, sets };
1445
+ }
1224
1446
  function matchValue(value, clause) {
1225
1447
  const op = clause.operator;
1226
1448
  if (op === "IS NULL") return value === null || value === void 0;
@@ -1374,16 +1596,36 @@ var SimSqlEngine = class {
1374
1596
  const valueBody = match[4].trim();
1375
1597
  const cursor = new ParamCursor(params);
1376
1598
  const table = this.ensureTable(tableName);
1599
+ const { tuples, conflict } = splitInsertTuples(valueBody);
1600
+ if (tuples.length === 0) throw new SimDbError("DB_UNSAFE_OP", "INSERT \u7F3A\u5C11 VALUES \u5143\u7EC4");
1601
+ const conflictSpec = conflict === null ? null : parseConflictClause(
1602
+ conflict,
1603
+ cursor,
1604
+ table.columns.filter((c) => c.primaryKey).map((c) => c.name)
1605
+ );
1377
1606
  let inserted = 0;
1378
- for (const group of splitListItems(valueBody)) {
1379
- const inner = group.trim().replace(/^\(|\)$/g, "");
1380
- const values = splitListItems(inner).map(
1607
+ for (const tuple of tuples) {
1608
+ const values = splitListItems(tuple).map(
1381
1609
  (item) => item.trim() === "?" ? cursor.take() : stripQuotes(item)
1382
1610
  );
1383
1611
  const row = {};
1384
1612
  cols.forEach((col, i) => {
1385
1613
  row[col] = values[i] ?? null;
1386
1614
  });
1615
+ if (conflictSpec !== null) {
1616
+ const existing = table.rows.find(
1617
+ (r) => conflictSpec.cols.every((c) => r[c] === row[c])
1618
+ );
1619
+ if (existing !== void 0) {
1620
+ const oldRow = { ...existing };
1621
+ for (const set of conflictSpec.sets) {
1622
+ existing[set.col] = resolveSetValue(set.value, oldRow, row);
1623
+ }
1624
+ inserted += 1;
1625
+ void this.persist();
1626
+ continue;
1627
+ }
1628
+ }
1387
1629
  this.applyAutoincrement(table, row);
1388
1630
  table.rows.push(row);
1389
1631
  inserted += 1;
@@ -1452,6 +1694,20 @@ var SimSqlEngine = class {
1452
1694
  return project(this.catalog(), selectRaw);
1453
1695
  }
1454
1696
  const table = this.ensureTable(tableName);
1697
+ let rows = table.rows;
1698
+ const joins = parseLeftJoins(tail);
1699
+ if (joins.length > 0) {
1700
+ rows = table.rows.map((row) => {
1701
+ const merged = { ...row };
1702
+ for (const j of joins) {
1703
+ const joined = this.tables[j.table]?.rows.find((jr) => jr[j.leftCol] === merged[j.rightCol]);
1704
+ if (joined !== void 0) {
1705
+ for (const [k, v] of Object.entries(joined)) merged[`${j.alias}.${k}`] = v;
1706
+ }
1707
+ }
1708
+ return merged;
1709
+ });
1710
+ }
1455
1711
  const whereMatch = /\bWHERE\b/i.exec(tail);
1456
1712
  const orderMatch = /\bORDER\s+BY\b/i.exec(tail);
1457
1713
  const limitMatch = /\bLIMIT\b/i.exec(tail);
@@ -1460,7 +1716,6 @@ var SimSqlEngine = class {
1460
1716
  whereMatch.index + whereMatch[0].length,
1461
1717
  indexAfter(whereMatch.index, [orderMatch, limitMatch, offsetMatch], tail)
1462
1718
  );
1463
- let rows = table.rows;
1464
1719
  if (whereRaw.trim().length > 0) {
1465
1720
  const clauses = parseWhereClauses(whereRaw, cursor);
1466
1721
  rows = rows.filter((row) => matchWhere(clauses, row));
@@ -1470,9 +1725,9 @@ var SimSqlEngine = class {
1470
1725
  orderMatch.index + orderMatch[0].length,
1471
1726
  indexAfter(orderMatch.index, [limitMatch, offsetMatch], tail)
1472
1727
  );
1473
- const oc = /^\s*((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_]*))\s+(asc|desc)/i.exec(orderRaw);
1728
+ const oc = /^\s*((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_.]*))\s+(asc|desc)/i.exec(orderRaw);
1474
1729
  if (oc !== null) {
1475
- const col = ident(oc[1]);
1730
+ const col = unqualifyColumn(ident(oc[1]));
1476
1731
  const dir = oc[3].toLowerCase();
1477
1732
  rows = [...rows].toSorted((a, b) => {
1478
1733
  const av = a[col];
@@ -1517,6 +1772,15 @@ function indexAfter(start, matches, tail) {
1517
1772
  const end = candidates.length === 0 ? -1 : Math.min(...candidates);
1518
1773
  return end === -1 ? tail.length : end;
1519
1774
  }
1775
+ function parseSelectItem(raw) {
1776
+ const t = raw.trim();
1777
+ const as = /\s+AS\s+([A-Za-z_][A-Za-z0-9_]*)$/i.exec(t);
1778
+ let name = as === null ? t : t.slice(0, as.index).trim();
1779
+ if (unqualifyColumn(name) === "*") return { name: "", qualified: "", alias: "", star: true };
1780
+ const qualified = /^[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? ident(name) : "";
1781
+ const plain = unqualifyColumn(ident(name));
1782
+ return { name: plain, qualified, alias: as === null ? plain : ident(as[1] ?? ""), star: false };
1783
+ }
1520
1784
  function project(rows, selectRaw) {
1521
1785
  if (/^count\s*\(\s*\*/i.test(selectRaw) || /^count\s*\(\s*1\)/i.test(selectRaw)) {
1522
1786
  const alias = selectRaw.match(/\bAS\s+([A-Za-z_][A-Za-z0-9_]*)/i)?.[1] ?? "n";
@@ -1527,10 +1791,21 @@ function project(rows, selectRaw) {
1527
1791
  return [{ [constMatch[2]]: Number(constMatch[1]) }];
1528
1792
  }
1529
1793
  if (selectRaw.trim() === "*") return rows;
1530
- const cols = selectRaw.split(",").map((s) => ident(s.trim()));
1794
+ const items = selectRaw.split(",").map(parseSelectItem);
1795
+ const valueOf = (row, item) => item.qualified !== "" && row[item.qualified] !== void 0 ? row[item.qualified] : row[item.name];
1796
+ if (items.some((item) => item.star)) {
1797
+ return rows.map((row) => {
1798
+ const out = { ...row };
1799
+ for (const item of items) {
1800
+ if (item.star) continue;
1801
+ out[item.alias] = valueOf(row, item);
1802
+ }
1803
+ return out;
1804
+ });
1805
+ }
1531
1806
  return rows.map((row) => {
1532
1807
  const out = {};
1533
- for (const col of cols) out[col] = row[col];
1808
+ for (const item of items) out[item.alias] = valueOf(row, item);
1534
1809
  return out;
1535
1810
  });
1536
1811
  }
@@ -3710,6 +3985,7 @@ function createBearerUserResolver(issuer) {
3710
3985
  }
3711
3986
  async function collectFunctions(dir) {
3712
3987
  const files = {};
3988
+ const isRuntimeSource = (name) => (name.endsWith(".ts") || name.endsWith(".js")) && !name.endsWith(".d.ts") && !name.endsWith(".test.ts");
3713
3989
  const walk = async (sub, prefix) => {
3714
3990
  let entries;
3715
3991
  try {
@@ -3722,7 +3998,7 @@ async function collectFunctions(dir) {
3722
3998
  const full = join8(sub, entry.name);
3723
3999
  if (entry.isDirectory()) {
3724
4000
  await walk(full, rel);
3725
- } else if (entry.isFile() && entry.name.endsWith(".ts")) {
4001
+ } else if (entry.isFile() && isRuntimeSource(entry.name)) {
3726
4002
  files[rel] = await readFile5(full, "utf8");
3727
4003
  }
3728
4004
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adep/cli",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "type": "module",
5
5
  "description": "`adep` 命令行工具包位:登录 / 初始化 / 本地调试 / 部署 / 数据库维护 / 云存储 / 静态托管 / 微前端组件(widget),实现见任务单 CLI-001 ~ CLI-003 与 FE-002;子路径 `@adep/cli/vite` 提供云函数 vite 插件(CLI-014)",
6
6
  "bin": {
@@ -21,10 +21,10 @@
21
21
  "commander": "14.0.2",
22
22
  "esbuild": "0.25.12",
23
23
  "@adep/cf-compat": "0.1.1",
24
- "@adep/vite-plugin": "0.1.3"
24
+ "@adep/vite-plugin": "0.1.4"
25
25
  },
26
26
  "devDependencies": {
27
- "@adep/runtime": "0.2.3",
27
+ "@adep/runtime": "0.2.4",
28
28
  "@adep/types": "0.2.3"
29
29
  },
30
30
  "scripts": {