@narrative.io/data-collaboration-sdk-ts 3.5.0 → 3.5.1

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.
@@ -182,21 +182,35 @@ export function parseOutput(n) {
182
182
  const parse = oneOf(parseColumnRef, parseLit, parseFunction, parsePlaceholder);
183
183
  return parse(n);
184
184
  }
185
+ function escapeRegExp(s) {
186
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
187
+ }
185
188
  function parseFunction(n) {
186
189
  if (n.type !== "function") {
187
190
  return nqlOrFail(n);
188
191
  }
189
- // Only structure functions whose original text is exactly the standard
190
- // call syntax `NAME(arg, arg, ...)`. Functions with special syntax
192
+ // Only structure functions whose original text is the standard call
193
+ // syntax `NAME(arg, arg, ...)`, optionally followed by an alias the
194
+ // server serializes `expr AS alias` as the inner node with the alias
195
+ // wrapper's `as`/`nql` merged on top, so an aliased function's `nql`
196
+ // span reads `NAME(args) AS alias`. Functions with special syntax —
191
197
  // EXTRACT(unit FROM x), CAST(x AS type), TRIM(BOTH ' ' FROM x) — cannot
192
198
  // be regenerated from name + args and must stay Raw passthroughs, or
193
- // compiling would emit comma syntax and corrupt the query.
199
+ // compiling would emit comma syntax and corrupt the query. The match
200
+ // tolerates whitespace differences (and a missing/implicit AS keyword)
201
+ // because compiling name + args back to `NAME(arg, arg, ...) AS "alias"`
202
+ // only ever normalizes those, never changes semantics.
194
203
  const argTexts = n.args.map((a) => "nql" in a ? a.nql : undefined);
195
204
  if (argTexts.some((t) => t === undefined)) {
196
205
  return nqlOrFail(n);
197
206
  }
198
- const reconstructed = `${n.name}(${argTexts.join(", ")})`;
199
- if (reconstructed !== n.nql) {
207
+ const aliasSuffix = n.as !== undefined
208
+ ? `(?:\\s+(?:AS\\s+)?(?:"${escapeRegExp(n.as)}"|${escapeRegExp(n.as)}))?`
209
+ : "";
210
+ const standardCall = new RegExp(`^${escapeRegExp(n.name)}\\s*\\(\\s*${argTexts
211
+ .map(escapeRegExp)
212
+ .join("\\s*,\\s*")}\\s*\\)${aliasSuffix}$`, "i");
213
+ if (!standardCall.test(n.nql)) {
200
214
  return nqlOrFail(n);
201
215
  }
202
216
  const func = {
@@ -611,10 +625,18 @@ function oneOf(...fs) {
611
625
  function nqlOrFail(n) {
612
626
  if ("nql" in n) {
613
627
  const as = "as" in n ? n.as : undefined;
628
+ // The server serializes `expr AS alias` by merging the alias wrapper's
629
+ // `as`/`nql` onto the inner node, so an aliased node's span carries a
630
+ // trailing ` AS alias`. Strip it: a Raw node's `nql` holds the bare
631
+ // expression and `as` holds the alias — otherwise compiling the node
632
+ // re-appends the alias and emits a corrupt double alias.
633
+ const nqlText = as !== undefined
634
+ ? n.nql.replace(new RegExp(`\\s+(?:AS\\s+)?(?:"${escapeRegExp(as)}"|${escapeRegExp(as)})\\s*$`, "i"), "")
635
+ : n.nql;
614
636
  const nql = {
615
637
  type: "nql",
616
638
  as,
617
- nql: n.nql,
639
+ nql: nqlText,
618
640
  };
619
641
  return nql;
620
642
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@narrative.io/data-collaboration-sdk-ts",
3
- "version": "3.5.0",
3
+ "version": "3.5.1",
4
4
  "main": "build/index.js",
5
5
  "repository": "github:narrative-io/data-collaboration-sdk-ts",
6
6
  "source": "src/index.ts",
@@ -43,7 +43,7 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "zod": "4.4.3",
46
- "bignumber.js": "11.1.4"
46
+ "bignumber.js": "11.1.5"
47
47
  },
48
48
  "overrides": {
49
49
  "semver@<7.5.2": "7.5.2"