sqlstack 1.0.15 → 1.0.16

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.
@@ -1 +1 @@
1
- {"version":3,"file":"sqlBinder.d.ts","sourceRoot":"","sources":["../../../src/binders/sqlBinder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE,GAAG,UAAU,CAAC;CAC1E;AAED,KAAK,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE/C,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,CAiLxD;AAED,eAAO,MAAM,iBAAiB,iBAA8B,CAAC;AAC7D,eAAO,MAAM,kBAAkB,iBAA+B,CAAC;AAC/D,eAAO,MAAM,oBAAoB,iBAAiC,CAAC;AAGnE,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
1
+ {"version":3,"file":"sqlBinder.d.ts","sourceRoot":"","sources":["../../../src/binders/sqlBinder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE,GAAG,UAAU,CAAC;CAC1E;AAED,KAAK,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE/C,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,CAqQxD;AAED,eAAO,MAAM,iBAAiB,iBAA8B,CAAC;AAC7D,eAAO,MAAM,kBAAkB,iBAA+B,CAAC;AAC/D,eAAO,MAAM,oBAAoB,iBAAiC,CAAC;AAGnE,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
@@ -103,6 +103,82 @@ function createBinder(dialect) {
103
103
  continue;
104
104
  }
105
105
  if (ch === ':') {
106
+ // Check for :update(...) syntax (case-insensitive)
107
+ const updateMatch = /^:update\s*\(/i.exec(sql.slice(i));
108
+ if (updateMatch) {
109
+ if (isArrayArgs) {
110
+ throw new Error(':update() syntax only works with named parameters');
111
+ }
112
+ // Parse the column list inside parentheses
113
+ let j = i + updateMatch[0].length; // Skip ':update('
114
+ const columnStart = j;
115
+ let parenDepth = 1;
116
+ let inString = false;
117
+ let stringChar = '';
118
+ // Find matching closing parenthesis
119
+ while (j < len && parenDepth > 0) {
120
+ const c = sql[j];
121
+ const cNext = j + 1 < len ? sql[j + 1] : '';
122
+ if (!inString) {
123
+ if (c === "'" || c === '"') {
124
+ inString = true;
125
+ stringChar = c;
126
+ }
127
+ else if (c === '(') {
128
+ parenDepth++;
129
+ }
130
+ else if (c === ')') {
131
+ parenDepth--;
132
+ }
133
+ }
134
+ else {
135
+ if (c === stringChar) {
136
+ // Check for escaped quote
137
+ if (cNext === stringChar) {
138
+ j++; // Skip escaped quote
139
+ }
140
+ else {
141
+ inString = false;
142
+ }
143
+ }
144
+ }
145
+ if (parenDepth > 0)
146
+ j++;
147
+ }
148
+ if (parenDepth > 0) {
149
+ throw new Error('Unclosed :update() parentheses');
150
+ }
151
+ // Extract column list (between the parentheses)
152
+ const columnList = sql.slice(columnStart, j).trim();
153
+ const updateEnd = j + 1; // Include closing ')'
154
+ // Parse column names (split by comma, trim whitespace)
155
+ const columns = columnList
156
+ .split(',')
157
+ .map(col => col.trim())
158
+ .filter(col => col.length > 0);
159
+ if (columns.length === 0) {
160
+ throw new Error(':update() requires at least one column name');
161
+ }
162
+ // Build SET clause with only defined columns
163
+ const obj = args;
164
+ const setParts = [];
165
+ const updateParams = [];
166
+ for (const col of columns) {
167
+ // Check if column exists in args and is not undefined
168
+ if (Object.prototype.hasOwnProperty.call(obj, col) && obj[col] !== undefined) {
169
+ setParts.push(`${col} = ${placeholder(pgIndex)}`);
170
+ updateParams.push(obj[col]);
171
+ }
172
+ }
173
+ if (setParts.length === 0) {
174
+ throw new Error('All columns in :update() are undefined');
175
+ }
176
+ // Replace :update(...) with SET clause
177
+ out.push('SET ', setParts.join(', '));
178
+ params.push(...updateParams);
179
+ i = updateEnd;
180
+ continue;
181
+ }
106
182
  // Attempt to parse a parameter token
107
183
  let j = i + 1;
108
184
  const start = j;
@@ -1 +1 @@
1
- {"version":3,"file":"sqlBinder.js","sourceRoot":"","sources":["../../../src/binders/sqlBinder.ts"],"names":[],"mappings":";;;AAaA,oCAiLC;AA9LD,iDAAuD;AAqM9C,mGArMA,8BAAkB,OAqMA;AAxL3B,SAAgB,YAAY,CAAC,OAAgB;IAC3C,MAAM,WAAW,GAAG,CAAC,QAAuB,EAAE,EAAE;QAC9C,IAAI,OAAO,KAAK,UAAU;YAAE,OAAO,IAAI,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC;QACtD,OAAO,GAAG,CAAC,CAAC,iBAAiB;IAC/B,CAAC,CAAC;IAEF,OAAO;QACL,IAAI,CAAC,GAAW,EAAE,IAAyC;YACzD,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACxC,MAAM,MAAM,GAAc,EAAE,CAAC;YAC7B,MAAM,GAAG,GAAa,EAAE,CAAC;YAEzB,IAAI,CAAC,GAAG,CAAC,CAAC;YACV,IAAI,IAAI,GAAG,KAAK,CAAC,CAAC,sBAAsB;YACxC,IAAI,IAAI,GAAG,KAAK,CAAC,CAAC,0BAA0B;YAC5C,IAAI,IAAI,GAAG,KAAK,CAAC,CAAC,wBAAwB;YAC1C,IAAI,IAAI,GAAG,KAAK,CAAC,CAAC,0BAA0B;YAC5C,MAAM,OAAO,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;YAEzB,IAAI,QAAQ,GAAG,KAAK,CAAC;YACrB,IAAI,aAAa,GAAG,KAAK,CAAC;YAE1B,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC;YACvB,OAAO,CAAC,GAAG,GAAG,EAAE,CAAC;gBACf,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;gBAClB,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAE3C,wCAAwC;gBACxC,IAAI,IAAI,EAAE,CAAC;oBACT,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBACb,CAAC,EAAE,CAAC;oBACJ,IAAI,EAAE,KAAK,IAAI;wBAAE,IAAI,GAAG,KAAK,CAAC;oBAC9B,SAAS;gBACX,CAAC;gBACD,IAAI,IAAI,EAAE,CAAC;oBACT,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBACb,CAAC,EAAE,CAAC;oBACJ,IAAI,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;wBAC/B,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBACf,CAAC,EAAE,CAAC;wBACJ,IAAI,GAAG,KAAK,CAAC;oBACf,CAAC;oBACD,SAAS;gBACX,CAAC;gBACD,IAAI,IAAI,EAAE,CAAC;oBACT,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBACb,CAAC,EAAE,CAAC;oBACJ,0BAA0B;oBAC1B,IAAI,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;wBAC/B,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBACf,CAAC,EAAE,CAAC;oBACN,CAAC;yBAAM,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;wBACtB,IAAI,GAAG,KAAK,CAAC;oBACf,CAAC;oBACD,SAAS;gBACX,CAAC;gBACD,IAAI,IAAI,EAAE,CAAC;oBACT,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBACb,CAAC,EAAE,CAAC;oBACJ,8BAA8B;oBAC9B,IAAI,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;wBAC/B,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBACf,CAAC,EAAE,CAAC;oBACN,CAAC;yBAAM,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;wBACtB,IAAI,GAAG,KAAK,CAAC;oBACf,CAAC;oBACD,SAAS;gBACX,CAAC;gBAED,4BAA4B;gBAC5B,IAAI,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;oBAC/B,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;oBACnB,CAAC,IAAI,CAAC,CAAC;oBACP,IAAI,GAAG,IAAI,CAAC;oBACZ,SAAS;gBACX,CAAC;gBACD,IAAI,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;oBAC/B,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;oBACnB,CAAC,IAAI,CAAC,CAAC;oBACP,IAAI,GAAG,IAAI,CAAC;oBACZ,SAAS;gBACX,CAAC;gBACD,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;oBACf,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBACb,CAAC,EAAE,CAAC;oBACJ,IAAI,GAAG,IAAI,CAAC;oBACZ,SAAS;gBACX,CAAC;gBACD,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;oBACf,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBACb,CAAC,EAAE,CAAC;oBACJ,IAAI,GAAG,IAAI,CAAC;oBACZ,SAAS;gBACX,CAAC;gBAED,qCAAqC;gBACrC,IAAI,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;oBAC/B,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBACf,CAAC,IAAI,CAAC,CAAC;oBACP,SAAS;gBACX,CAAC;gBAED,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;oBACf,qCAAqC;oBACrC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;oBACd,MAAM,KAAK,GAAG,CAAC,CAAC;oBAChB,OAAO,CAAC,GAAG,GAAG,EAAE,CAAC;wBACf,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;wBACjB,IAAI,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;4BAC5F,CAAC,EAAE,CAAC;wBACN,CAAC;6BAAM,CAAC;4BACN,MAAM;wBACR,CAAC;oBACH,CAAC;oBACD,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;oBACjC,IAAI,CAAC,IAAI,EAAE,CAAC;wBACV,qCAAqC;wBACrC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;wBACd,CAAC,EAAE,CAAC;wBACJ,SAAS;oBACX,CAAC;oBAED,6BAA6B;oBAC7B,MAAM,CAAC,GAAG,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAC1C,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;oBAClB,IAAI,KAAK;wBAAE,aAAa,GAAG,IAAI,CAAC;;wBAAM,QAAQ,GAAG,IAAI,CAAC;oBACtD,IAAI,QAAQ,IAAI,aAAa,EAAE,CAAC;wBAC9B,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;oBAClF,CAAC;oBAED,IAAI,KAAc,CAAC;oBACnB,IAAI,KAAK,EAAE,CAAC;wBACV,IAAI,CAAC,WAAW;4BAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;wBACrF,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,iBAAiB;wBACxD,MAAM,GAAG,GAAG,IAAiB,CAAC;wBAC9B,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,IAAI,GAAG,CAAC,MAAM;4BAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,IAAI,EAAE,CAAC,CAAC;wBAC9F,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;oBACrB,CAAC;yBAAM,CAAC;wBACN,IAAI,WAAW;4BAAE,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;wBAClF,MAAM,GAAG,GAAG,IAA+B,CAAC;wBAC5C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC;4BACrD,MAAM,IAAI,KAAK,CAAC,4BAA4B,IAAI,EAAE,CAAC,CAAC;wBACtD,CAAC;wBACD,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;oBACpB,CAAC;oBAED,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;wBACxB,MAAM,IAAI,KAAK,CAAC,cAAc,IAAI,eAAe,CAAC,CAAC;oBACrD,CAAC;oBAED,wBAAwB;oBACxB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;wBACzB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;4BAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,IAAI,oBAAoB,CAAC,CAAC;wBACtF,MAAM,YAAY,GAAa,EAAE,CAAC;wBAClC,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;4BACtB,IAAI,CAAC,KAAK,SAAS;gCAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,IAAI,qBAAqB,CAAC,CAAC;4BACpF,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;4BACxC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;wBAC1C,CAAC;wBACD,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;oBACpC,CAAC;yBAAM,CAAC;wBACN,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;wBAC/B,MAAM,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;oBAClD,CAAC;oBAED,CAAC,GAAG,CAAC,CAAC;oBACN,SAAS;gBACX,CAAC;gBAED,qBAAqB;gBACrB,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACb,CAAC,EAAE,CAAC;YACN,CAAC;YAED,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;QACvC,CAAC;KACF,CAAC;AACJ,CAAC;AAEM,MAAM,iBAAiB,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;AAAhD,QAAA,iBAAiB,qBAA+B;AACtD,MAAM,kBAAkB,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;AAAlD,QAAA,kBAAkB,sBAAgC;AACxD,MAAM,oBAAoB,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;AAAtD,QAAA,oBAAoB,wBAAkC","sourcesContent":["import { extractNamedParams } from '../core/sqlParams';\n\nexport type BindResult = {\n sql: string;\n params: unknown[];\n};\n\nexport interface SqlBinder {\n bind(sql: string, args: Record<string, unknown> | unknown[]): BindResult;\n}\n\ntype Dialect = 'mysql' | 'sqlite' | 'postgres';\n\nexport function createBinder(dialect: Dialect): SqlBinder {\n const placeholder = (indexRef: { i: number }) => {\n if (dialect === 'postgres') return `$${indexRef.i++}`;\n return '?'; // mysql + sqlite\n };\n\n return {\n bind(sql: string, args: Record<string, unknown> | unknown[]): BindResult {\n const isArrayArgs = Array.isArray(args);\n const params: unknown[] = [];\n const out: string[] = [];\n\n let i = 0;\n let inSQ = false; // single quote string\n let inDQ = false; // double quote identifier\n let inLC = false; // line comment -- ...\\n\n let inBC = false; // block comment /* ... */\n const pgIndex = { i: 1 };\n\n let sawNamed = false;\n let sawPositional = false;\n\n const len = sql.length;\n while (i < len) {\n const ch = sql[i];\n const next = i + 1 < len ? sql[i + 1] : '';\n\n // Handle exiting comments/strings first\n if (inLC) {\n out.push(ch);\n i++;\n if (ch === '\\n') inLC = false;\n continue;\n }\n if (inBC) {\n out.push(ch);\n i++;\n if (ch === '*' && next === '/') {\n out.push(next);\n i++;\n inBC = false;\n }\n continue;\n }\n if (inSQ) {\n out.push(ch);\n i++;\n // escape '' inside string\n if (ch === \"'\" && next === \"'\") {\n out.push(next);\n i++;\n } else if (ch === \"'\") {\n inSQ = false;\n }\n continue;\n }\n if (inDQ) {\n out.push(ch);\n i++;\n // escape \"\" inside identifier\n if (ch === '\"' && next === '\"') {\n out.push(next);\n i++;\n } else if (ch === '\"') {\n inDQ = false;\n }\n continue;\n }\n\n // Not inside string/comment\n if (ch === '-' && next === '-') {\n out.push(ch, next);\n i += 2;\n inLC = true;\n continue;\n }\n if (ch === '/' && next === '*') {\n out.push(ch, next);\n i += 2;\n inBC = true;\n continue;\n }\n if (ch === \"'\") {\n out.push(ch);\n i++;\n inSQ = true;\n continue;\n }\n if (ch === '\"') {\n out.push(ch);\n i++;\n inDQ = true;\n continue;\n }\n\n // Postgres cast :: — skip as literal\n if (ch === ':' && next === ':') {\n out.push('::');\n i += 2;\n continue;\n }\n\n if (ch === ':') {\n // Attempt to parse a parameter token\n let j = i + 1;\n const start = j;\n while (j < len) {\n const c = sql[j];\n if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c === '_') {\n j++;\n } else {\n break;\n }\n }\n const name = sql.slice(start, j);\n if (!name) {\n // not a parameter — keep literal ':'\n out.push(':');\n i++;\n continue;\n }\n\n // Decide positional vs named\n const m = /^arg([1-9][0-9]*)$/.exec(name);\n const isPos = !!m;\n if (isPos) sawPositional = true; else sawNamed = true;\n if (sawNamed && sawPositional) {\n throw new Error('Cannot mix named and positional parameters in a single query');\n }\n\n let value: unknown;\n if (isPos) {\n if (!isArrayArgs) throw new Error('Positional placeholders require array arguments');\n const index = parseInt(m![1], 10) - 1; // 1-based in SQL\n const arr = args as unknown[];\n if (index < 0 || index >= arr.length) throw new Error(`Missing positional argument :${name}`);\n value = arr[index];\n } else {\n if (isArrayArgs) throw new Error('Named placeholders require a parameter object');\n const obj = args as Record<string, unknown>;\n if (!Object.prototype.hasOwnProperty.call(obj, name)) {\n throw new Error(`Missing named parameter :${name}`);\n }\n value = obj[name];\n }\n\n if (value === undefined) {\n throw new Error(`Parameter :${name} is undefined`);\n }\n\n // Expand placeholder(s)\n if (Array.isArray(value)) {\n if (value.length === 0) throw new Error(`Array parameter :${name} must not be empty`);\n const placeholders: string[] = [];\n for (const v of value) {\n if (v === undefined) throw new Error(`Array parameter :${name} contains undefined`);\n placeholders.push(placeholder(pgIndex));\n params.push(v === undefined ? null : v);\n }\n out.push(placeholders.join(', '));\n } else {\n out.push(placeholder(pgIndex));\n params.push(value === undefined ? null : value);\n }\n\n i = j;\n continue;\n }\n\n // default: copy char\n out.push(ch);\n i++;\n }\n\n return { sql: out.join(''), params };\n },\n };\n}\n\nexport const createMysqlBinder = () => createBinder('mysql');\nexport const createSqliteBinder = () => createBinder('sqlite');\nexport const createPostgresBinder = () => createBinder('postgres');\n\n// Re-export the shared helper for use in decorators\nexport { extractNamedParams };\n"]}
1
+ {"version":3,"file":"sqlBinder.js","sourceRoot":"","sources":["../../../src/binders/sqlBinder.ts"],"names":[],"mappings":"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","sourcesContent":["import { extractNamedParams } from '../core/sqlParams';\n\nexport type BindResult = {\n sql: string;\n params: unknown[];\n};\n\nexport interface SqlBinder {\n bind(sql: string, args: Record<string, unknown> | unknown[]): BindResult;\n}\n\ntype Dialect = 'mysql' | 'sqlite' | 'postgres';\n\nexport function createBinder(dialect: Dialect): SqlBinder {\n const placeholder = (indexRef: { i: number }) => {\n if (dialect === 'postgres') return `$${indexRef.i++}`;\n return '?'; // mysql + sqlite\n };\n\n return {\n bind(sql: string, args: Record<string, unknown> | unknown[]): BindResult {\n const isArrayArgs = Array.isArray(args);\n const params: unknown[] = [];\n const out: string[] = [];\n\n let i = 0;\n let inSQ = false; // single quote string\n let inDQ = false; // double quote identifier\n let inLC = false; // line comment -- ...\\n\n let inBC = false; // block comment /* ... */\n const pgIndex = { i: 1 };\n\n let sawNamed = false;\n let sawPositional = false;\n\n const len = sql.length;\n while (i < len) {\n const ch = sql[i];\n const next = i + 1 < len ? sql[i + 1] : '';\n\n // Handle exiting comments/strings first\n if (inLC) {\n out.push(ch);\n i++;\n if (ch === '\\n') inLC = false;\n continue;\n }\n if (inBC) {\n out.push(ch);\n i++;\n if (ch === '*' && next === '/') {\n out.push(next);\n i++;\n inBC = false;\n }\n continue;\n }\n if (inSQ) {\n out.push(ch);\n i++;\n // escape '' inside string\n if (ch === \"'\" && next === \"'\") {\n out.push(next);\n i++;\n } else if (ch === \"'\") {\n inSQ = false;\n }\n continue;\n }\n if (inDQ) {\n out.push(ch);\n i++;\n // escape \"\" inside identifier\n if (ch === '\"' && next === '\"') {\n out.push(next);\n i++;\n } else if (ch === '\"') {\n inDQ = false;\n }\n continue;\n }\n\n // Not inside string/comment\n if (ch === '-' && next === '-') {\n out.push(ch, next);\n i += 2;\n inLC = true;\n continue;\n }\n if (ch === '/' && next === '*') {\n out.push(ch, next);\n i += 2;\n inBC = true;\n continue;\n }\n if (ch === \"'\") {\n out.push(ch);\n i++;\n inSQ = true;\n continue;\n }\n if (ch === '\"') {\n out.push(ch);\n i++;\n inDQ = true;\n continue;\n }\n\n // Postgres cast :: — skip as literal\n if (ch === ':' && next === ':') {\n out.push('::');\n i += 2;\n continue;\n }\n\n if (ch === ':') {\n // Check for :update(...) syntax (case-insensitive)\n const updateMatch = /^:update\\s*\\(/i.exec(sql.slice(i));\n if (updateMatch) {\n if (isArrayArgs) {\n throw new Error(':update() syntax only works with named parameters');\n }\n \n // Parse the column list inside parentheses\n let j = i + updateMatch[0].length; // Skip ':update('\n const columnStart = j;\n let parenDepth = 1;\n let inString = false;\n let stringChar = '';\n \n // Find matching closing parenthesis\n while (j < len && parenDepth > 0) {\n const c = sql[j];\n const cNext = j + 1 < len ? sql[j + 1] : '';\n \n if (!inString) {\n if (c === \"'\" || c === '\"') {\n inString = true;\n stringChar = c;\n } else if (c === '(') {\n parenDepth++;\n } else if (c === ')') {\n parenDepth--;\n }\n } else {\n if (c === stringChar) {\n // Check for escaped quote\n if (cNext === stringChar) {\n j++; // Skip escaped quote\n } else {\n inString = false;\n }\n }\n }\n if (parenDepth > 0) j++;\n }\n \n if (parenDepth > 0) {\n throw new Error('Unclosed :update() parentheses');\n }\n \n // Extract column list (between the parentheses)\n const columnList = sql.slice(columnStart, j).trim();\n const updateEnd = j + 1; // Include closing ')'\n \n // Parse column names (split by comma, trim whitespace)\n const columns = columnList\n .split(',')\n .map(col => col.trim())\n .filter(col => col.length > 0);\n \n if (columns.length === 0) {\n throw new Error(':update() requires at least one column name');\n }\n \n // Build SET clause with only defined columns\n const obj = args as Record<string, unknown>;\n const setParts: string[] = [];\n const updateParams: unknown[] = [];\n \n for (const col of columns) {\n // Check if column exists in args and is not undefined\n if (Object.prototype.hasOwnProperty.call(obj, col) && obj[col] !== undefined) {\n setParts.push(`${col} = ${placeholder(pgIndex)}`);\n updateParams.push(obj[col]);\n }\n }\n \n if (setParts.length === 0) {\n throw new Error('All columns in :update() are undefined');\n }\n \n // Replace :update(...) with SET clause\n out.push('SET ', setParts.join(', '));\n params.push(...updateParams);\n \n i = updateEnd;\n continue;\n }\n \n // Attempt to parse a parameter token\n let j = i + 1;\n const start = j;\n while (j < len) {\n const c = sql[j];\n if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c === '_') {\n j++;\n } else {\n break;\n }\n }\n const name = sql.slice(start, j);\n if (!name) {\n // not a parameter — keep literal ':'\n out.push(':');\n i++;\n continue;\n }\n\n // Decide positional vs named\n const m = /^arg([1-9][0-9]*)$/.exec(name);\n const isPos = !!m;\n if (isPos) sawPositional = true; else sawNamed = true;\n if (sawNamed && sawPositional) {\n throw new Error('Cannot mix named and positional parameters in a single query');\n }\n\n let value: unknown;\n if (isPos) {\n if (!isArrayArgs) throw new Error('Positional placeholders require array arguments');\n const index = parseInt(m![1], 10) - 1; // 1-based in SQL\n const arr = args as unknown[];\n if (index < 0 || index >= arr.length) throw new Error(`Missing positional argument :${name}`);\n value = arr[index];\n } else {\n if (isArrayArgs) throw new Error('Named placeholders require a parameter object');\n const obj = args as Record<string, unknown>;\n if (!Object.prototype.hasOwnProperty.call(obj, name)) {\n throw new Error(`Missing named parameter :${name}`);\n }\n value = obj[name];\n }\n\n if (value === undefined) {\n throw new Error(`Parameter :${name} is undefined`);\n }\n\n // Expand placeholder(s)\n if (Array.isArray(value)) {\n if (value.length === 0) throw new Error(`Array parameter :${name} must not be empty`);\n const placeholders: string[] = [];\n for (const v of value) {\n if (v === undefined) throw new Error(`Array parameter :${name} contains undefined`);\n placeholders.push(placeholder(pgIndex));\n params.push(v === undefined ? null : v);\n }\n out.push(placeholders.join(', '));\n } else {\n out.push(placeholder(pgIndex));\n params.push(value === undefined ? null : value);\n }\n\n i = j;\n continue;\n }\n\n // default: copy char\n out.push(ch);\n i++;\n }\n\n return { sql: out.join(''), params };\n },\n };\n}\n\nexport const createMysqlBinder = () => createBinder('mysql');\nexport const createSqliteBinder = () => createBinder('sqlite');\nexport const createPostgresBinder = () => createBinder('postgres');\n\n// Re-export the shared helper for use in decorators\nexport { extractNamedParams };\n"]}
@@ -98,6 +98,82 @@ export function createBinder(dialect) {
98
98
  continue;
99
99
  }
100
100
  if (ch === ':') {
101
+ // Check for :update(...) syntax (case-insensitive)
102
+ const updateMatch = /^:update\s*\(/i.exec(sql.slice(i));
103
+ if (updateMatch) {
104
+ if (isArrayArgs) {
105
+ throw new Error(':update() syntax only works with named parameters');
106
+ }
107
+ // Parse the column list inside parentheses
108
+ let j = i + updateMatch[0].length; // Skip ':update('
109
+ const columnStart = j;
110
+ let parenDepth = 1;
111
+ let inString = false;
112
+ let stringChar = '';
113
+ // Find matching closing parenthesis
114
+ while (j < len && parenDepth > 0) {
115
+ const c = sql[j];
116
+ const cNext = j + 1 < len ? sql[j + 1] : '';
117
+ if (!inString) {
118
+ if (c === "'" || c === '"') {
119
+ inString = true;
120
+ stringChar = c;
121
+ }
122
+ else if (c === '(') {
123
+ parenDepth++;
124
+ }
125
+ else if (c === ')') {
126
+ parenDepth--;
127
+ }
128
+ }
129
+ else {
130
+ if (c === stringChar) {
131
+ // Check for escaped quote
132
+ if (cNext === stringChar) {
133
+ j++; // Skip escaped quote
134
+ }
135
+ else {
136
+ inString = false;
137
+ }
138
+ }
139
+ }
140
+ if (parenDepth > 0)
141
+ j++;
142
+ }
143
+ if (parenDepth > 0) {
144
+ throw new Error('Unclosed :update() parentheses');
145
+ }
146
+ // Extract column list (between the parentheses)
147
+ const columnList = sql.slice(columnStart, j).trim();
148
+ const updateEnd = j + 1; // Include closing ')'
149
+ // Parse column names (split by comma, trim whitespace)
150
+ const columns = columnList
151
+ .split(',')
152
+ .map(col => col.trim())
153
+ .filter(col => col.length > 0);
154
+ if (columns.length === 0) {
155
+ throw new Error(':update() requires at least one column name');
156
+ }
157
+ // Build SET clause with only defined columns
158
+ const obj = args;
159
+ const setParts = [];
160
+ const updateParams = [];
161
+ for (const col of columns) {
162
+ // Check if column exists in args and is not undefined
163
+ if (Object.prototype.hasOwnProperty.call(obj, col) && obj[col] !== undefined) {
164
+ setParts.push(`${col} = ${placeholder(pgIndex)}`);
165
+ updateParams.push(obj[col]);
166
+ }
167
+ }
168
+ if (setParts.length === 0) {
169
+ throw new Error('All columns in :update() are undefined');
170
+ }
171
+ // Replace :update(...) with SET clause
172
+ out.push('SET ', setParts.join(', '));
173
+ params.push(...updateParams);
174
+ i = updateEnd;
175
+ continue;
176
+ }
101
177
  // Attempt to parse a parameter token
102
178
  let j = i + 1;
103
179
  const start = j;
@@ -1 +1 @@
1
- {"version":3,"file":"sqlBinder.js","sourceRoot":"","sources":["../../../src/binders/sqlBinder.ts"],"names":[],"mappings":"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","sourcesContent":["import { extractNamedParams } from '../core/sqlParams';\n\nexport type BindResult = {\n sql: string;\n params: unknown[];\n};\n\nexport interface SqlBinder {\n bind(sql: string, args: Record<string, unknown> | unknown[]): BindResult;\n}\n\ntype Dialect = 'mysql' | 'sqlite' | 'postgres';\n\nexport function createBinder(dialect: Dialect): SqlBinder {\n const placeholder = (indexRef: { i: number }) => {\n if (dialect === 'postgres') return `$${indexRef.i++}`;\n return '?'; // mysql + sqlite\n };\n\n return {\n bind(sql: string, args: Record<string, unknown> | unknown[]): BindResult {\n const isArrayArgs = Array.isArray(args);\n const params: unknown[] = [];\n const out: string[] = [];\n\n let i = 0;\n let inSQ = false; // single quote string\n let inDQ = false; // double quote identifier\n let inLC = false; // line comment -- ...\\n\n let inBC = false; // block comment /* ... */\n const pgIndex = { i: 1 };\n\n let sawNamed = false;\n let sawPositional = false;\n\n const len = sql.length;\n while (i < len) {\n const ch = sql[i];\n const next = i + 1 < len ? sql[i + 1] : '';\n\n // Handle exiting comments/strings first\n if (inLC) {\n out.push(ch);\n i++;\n if (ch === '\\n') inLC = false;\n continue;\n }\n if (inBC) {\n out.push(ch);\n i++;\n if (ch === '*' && next === '/') {\n out.push(next);\n i++;\n inBC = false;\n }\n continue;\n }\n if (inSQ) {\n out.push(ch);\n i++;\n // escape '' inside string\n if (ch === \"'\" && next === \"'\") {\n out.push(next);\n i++;\n } else if (ch === \"'\") {\n inSQ = false;\n }\n continue;\n }\n if (inDQ) {\n out.push(ch);\n i++;\n // escape \"\" inside identifier\n if (ch === '\"' && next === '\"') {\n out.push(next);\n i++;\n } else if (ch === '\"') {\n inDQ = false;\n }\n continue;\n }\n\n // Not inside string/comment\n if (ch === '-' && next === '-') {\n out.push(ch, next);\n i += 2;\n inLC = true;\n continue;\n }\n if (ch === '/' && next === '*') {\n out.push(ch, next);\n i += 2;\n inBC = true;\n continue;\n }\n if (ch === \"'\") {\n out.push(ch);\n i++;\n inSQ = true;\n continue;\n }\n if (ch === '\"') {\n out.push(ch);\n i++;\n inDQ = true;\n continue;\n }\n\n // Postgres cast :: — skip as literal\n if (ch === ':' && next === ':') {\n out.push('::');\n i += 2;\n continue;\n }\n\n if (ch === ':') {\n // Attempt to parse a parameter token\n let j = i + 1;\n const start = j;\n while (j < len) {\n const c = sql[j];\n if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c === '_') {\n j++;\n } else {\n break;\n }\n }\n const name = sql.slice(start, j);\n if (!name) {\n // not a parameter — keep literal ':'\n out.push(':');\n i++;\n continue;\n }\n\n // Decide positional vs named\n const m = /^arg([1-9][0-9]*)$/.exec(name);\n const isPos = !!m;\n if (isPos) sawPositional = true; else sawNamed = true;\n if (sawNamed && sawPositional) {\n throw new Error('Cannot mix named and positional parameters in a single query');\n }\n\n let value: unknown;\n if (isPos) {\n if (!isArrayArgs) throw new Error('Positional placeholders require array arguments');\n const index = parseInt(m![1], 10) - 1; // 1-based in SQL\n const arr = args as unknown[];\n if (index < 0 || index >= arr.length) throw new Error(`Missing positional argument :${name}`);\n value = arr[index];\n } else {\n if (isArrayArgs) throw new Error('Named placeholders require a parameter object');\n const obj = args as Record<string, unknown>;\n if (!Object.prototype.hasOwnProperty.call(obj, name)) {\n throw new Error(`Missing named parameter :${name}`);\n }\n value = obj[name];\n }\n\n if (value === undefined) {\n throw new Error(`Parameter :${name} is undefined`);\n }\n\n // Expand placeholder(s)\n if (Array.isArray(value)) {\n if (value.length === 0) throw new Error(`Array parameter :${name} must not be empty`);\n const placeholders: string[] = [];\n for (const v of value) {\n if (v === undefined) throw new Error(`Array parameter :${name} contains undefined`);\n placeholders.push(placeholder(pgIndex));\n params.push(v === undefined ? null : v);\n }\n out.push(placeholders.join(', '));\n } else {\n out.push(placeholder(pgIndex));\n params.push(value === undefined ? null : value);\n }\n\n i = j;\n continue;\n }\n\n // default: copy char\n out.push(ch);\n i++;\n }\n\n return { sql: out.join(''), params };\n },\n };\n}\n\nexport const createMysqlBinder = () => createBinder('mysql');\nexport const createSqliteBinder = () => createBinder('sqlite');\nexport const createPostgresBinder = () => createBinder('postgres');\n\n// Re-export the shared helper for use in decorators\nexport { extractNamedParams };\n"]}
1
+ {"version":3,"file":"sqlBinder.js","sourceRoot":"","sources":["../../../src/binders/sqlBinder.ts"],"names":[],"mappings":"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","sourcesContent":["import { extractNamedParams } from '../core/sqlParams';\n\nexport type BindResult = {\n sql: string;\n params: unknown[];\n};\n\nexport interface SqlBinder {\n bind(sql: string, args: Record<string, unknown> | unknown[]): BindResult;\n}\n\ntype Dialect = 'mysql' | 'sqlite' | 'postgres';\n\nexport function createBinder(dialect: Dialect): SqlBinder {\n const placeholder = (indexRef: { i: number }) => {\n if (dialect === 'postgres') return `$${indexRef.i++}`;\n return '?'; // mysql + sqlite\n };\n\n return {\n bind(sql: string, args: Record<string, unknown> | unknown[]): BindResult {\n const isArrayArgs = Array.isArray(args);\n const params: unknown[] = [];\n const out: string[] = [];\n\n let i = 0;\n let inSQ = false; // single quote string\n let inDQ = false; // double quote identifier\n let inLC = false; // line comment -- ...\\n\n let inBC = false; // block comment /* ... */\n const pgIndex = { i: 1 };\n\n let sawNamed = false;\n let sawPositional = false;\n\n const len = sql.length;\n while (i < len) {\n const ch = sql[i];\n const next = i + 1 < len ? sql[i + 1] : '';\n\n // Handle exiting comments/strings first\n if (inLC) {\n out.push(ch);\n i++;\n if (ch === '\\n') inLC = false;\n continue;\n }\n if (inBC) {\n out.push(ch);\n i++;\n if (ch === '*' && next === '/') {\n out.push(next);\n i++;\n inBC = false;\n }\n continue;\n }\n if (inSQ) {\n out.push(ch);\n i++;\n // escape '' inside string\n if (ch === \"'\" && next === \"'\") {\n out.push(next);\n i++;\n } else if (ch === \"'\") {\n inSQ = false;\n }\n continue;\n }\n if (inDQ) {\n out.push(ch);\n i++;\n // escape \"\" inside identifier\n if (ch === '\"' && next === '\"') {\n out.push(next);\n i++;\n } else if (ch === '\"') {\n inDQ = false;\n }\n continue;\n }\n\n // Not inside string/comment\n if (ch === '-' && next === '-') {\n out.push(ch, next);\n i += 2;\n inLC = true;\n continue;\n }\n if (ch === '/' && next === '*') {\n out.push(ch, next);\n i += 2;\n inBC = true;\n continue;\n }\n if (ch === \"'\") {\n out.push(ch);\n i++;\n inSQ = true;\n continue;\n }\n if (ch === '\"') {\n out.push(ch);\n i++;\n inDQ = true;\n continue;\n }\n\n // Postgres cast :: — skip as literal\n if (ch === ':' && next === ':') {\n out.push('::');\n i += 2;\n continue;\n }\n\n if (ch === ':') {\n // Check for :update(...) syntax (case-insensitive)\n const updateMatch = /^:update\\s*\\(/i.exec(sql.slice(i));\n if (updateMatch) {\n if (isArrayArgs) {\n throw new Error(':update() syntax only works with named parameters');\n }\n \n // Parse the column list inside parentheses\n let j = i + updateMatch[0].length; // Skip ':update('\n const columnStart = j;\n let parenDepth = 1;\n let inString = false;\n let stringChar = '';\n \n // Find matching closing parenthesis\n while (j < len && parenDepth > 0) {\n const c = sql[j];\n const cNext = j + 1 < len ? sql[j + 1] : '';\n \n if (!inString) {\n if (c === \"'\" || c === '\"') {\n inString = true;\n stringChar = c;\n } else if (c === '(') {\n parenDepth++;\n } else if (c === ')') {\n parenDepth--;\n }\n } else {\n if (c === stringChar) {\n // Check for escaped quote\n if (cNext === stringChar) {\n j++; // Skip escaped quote\n } else {\n inString = false;\n }\n }\n }\n if (parenDepth > 0) j++;\n }\n \n if (parenDepth > 0) {\n throw new Error('Unclosed :update() parentheses');\n }\n \n // Extract column list (between the parentheses)\n const columnList = sql.slice(columnStart, j).trim();\n const updateEnd = j + 1; // Include closing ')'\n \n // Parse column names (split by comma, trim whitespace)\n const columns = columnList\n .split(',')\n .map(col => col.trim())\n .filter(col => col.length > 0);\n \n if (columns.length === 0) {\n throw new Error(':update() requires at least one column name');\n }\n \n // Build SET clause with only defined columns\n const obj = args as Record<string, unknown>;\n const setParts: string[] = [];\n const updateParams: unknown[] = [];\n \n for (const col of columns) {\n // Check if column exists in args and is not undefined\n if (Object.prototype.hasOwnProperty.call(obj, col) && obj[col] !== undefined) {\n setParts.push(`${col} = ${placeholder(pgIndex)}`);\n updateParams.push(obj[col]);\n }\n }\n \n if (setParts.length === 0) {\n throw new Error('All columns in :update() are undefined');\n }\n \n // Replace :update(...) with SET clause\n out.push('SET ', setParts.join(', '));\n params.push(...updateParams);\n \n i = updateEnd;\n continue;\n }\n \n // Attempt to parse a parameter token\n let j = i + 1;\n const start = j;\n while (j < len) {\n const c = sql[j];\n if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c === '_') {\n j++;\n } else {\n break;\n }\n }\n const name = sql.slice(start, j);\n if (!name) {\n // not a parameter — keep literal ':'\n out.push(':');\n i++;\n continue;\n }\n\n // Decide positional vs named\n const m = /^arg([1-9][0-9]*)$/.exec(name);\n const isPos = !!m;\n if (isPos) sawPositional = true; else sawNamed = true;\n if (sawNamed && sawPositional) {\n throw new Error('Cannot mix named and positional parameters in a single query');\n }\n\n let value: unknown;\n if (isPos) {\n if (!isArrayArgs) throw new Error('Positional placeholders require array arguments');\n const index = parseInt(m![1], 10) - 1; // 1-based in SQL\n const arr = args as unknown[];\n if (index < 0 || index >= arr.length) throw new Error(`Missing positional argument :${name}`);\n value = arr[index];\n } else {\n if (isArrayArgs) throw new Error('Named placeholders require a parameter object');\n const obj = args as Record<string, unknown>;\n if (!Object.prototype.hasOwnProperty.call(obj, name)) {\n throw new Error(`Missing named parameter :${name}`);\n }\n value = obj[name];\n }\n\n if (value === undefined) {\n throw new Error(`Parameter :${name} is undefined`);\n }\n\n // Expand placeholder(s)\n if (Array.isArray(value)) {\n if (value.length === 0) throw new Error(`Array parameter :${name} must not be empty`);\n const placeholders: string[] = [];\n for (const v of value) {\n if (v === undefined) throw new Error(`Array parameter :${name} contains undefined`);\n placeholders.push(placeholder(pgIndex));\n params.push(v === undefined ? null : v);\n }\n out.push(placeholders.join(', '));\n } else {\n out.push(placeholder(pgIndex));\n params.push(value === undefined ? null : value);\n }\n\n i = j;\n continue;\n }\n\n // default: copy char\n out.push(ch);\n i++;\n }\n\n return { sql: out.join(''), params };\n },\n };\n}\n\nexport const createMysqlBinder = () => createBinder('mysql');\nexport const createSqliteBinder = () => createBinder('sqlite');\nexport const createPostgresBinder = () => createBinder('postgres');\n\n// Re-export the shared helper for use in decorators\nexport { extractNamedParams };\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sqlstack",
3
- "version": "1.0.15",
3
+ "version": "1.0.16",
4
4
  "description": "",
5
5
  "license": "ISC",
6
6
  "author": "",
@@ -33,6 +33,7 @@
33
33
  }
34
34
  },
35
35
  "scripts": {
36
+ "prepublish": "npm run build",
36
37
  "build": "npm-run-all clean build:cjs build:esm",
37
38
  "build:cjs": "tsc -p tsconfig.json",
38
39
  "build:esm": "tsc -p tsconfig.esm.json && node scripts/fix-esm-extensions.js && node scripts/create-esm-package.cjs",