@prompd/core 0.5.2 → 0.5.4

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/dist/index.cjs CHANGED
@@ -3395,11 +3395,19 @@ var MAX_PACKAGE_SIZE = 50 * 1024 * 1024;
3395
3395
  function slugify(name) {
3396
3396
  return name.toLowerCase().replace(/[@/]+/g, "-").replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "");
3397
3397
  }
3398
- function resolvePackageDir(root, type, name) {
3399
- return joinPosix(root, ".prompd", getInstallDirForType(type), name);
3398
+ var DEFAULT_INSTALL_DIR = ".prompd";
3399
+ function checkInstallDir(dir) {
3400
+ const d = dir ?? DEFAULT_INSTALL_DIR;
3401
+ if (!/^\.[A-Za-z0-9][A-Za-z0-9._-]*$/.test(d)) {
3402
+ throw new Error(`Invalid installDir "${d}": expected a single dot-directory name like ".prompd".`);
3403
+ }
3404
+ return d;
3405
+ }
3406
+ function resolvePackageDir(root, installDir, type, name) {
3407
+ return joinPosix(root, installDir, getInstallDirForType(type), name);
3400
3408
  }
3401
- function resolveInstallDir(root, type, name, version) {
3402
- return joinPosix(resolvePackageDir(root, type, name), version);
3409
+ function resolveInstallDir(root, installDir, type, name, version) {
3410
+ return joinPosix(resolvePackageDir(root, installDir, type, name), version);
3403
3411
  }
3404
3412
  async function addWorkspaceDependency(store, root, name, version) {
3405
3413
  if (!store.readFile) return;
@@ -3441,6 +3449,7 @@ async function installPackage(opts) {
3441
3449
  }
3442
3450
  async function installInternal(opts, visited) {
3443
3451
  const { ref, root, store, download, global, tools, deployTool } = opts;
3452
+ const installDir = checkInstallDir(opts.installDir);
3444
3453
  const parsed = parsePackageReference(ref);
3445
3454
  const bytes = await download(parsed.name, parsed.version);
3446
3455
  if (bytes.length > MAX_PACKAGE_SIZE) {
@@ -3467,11 +3476,11 @@ async function installInternal(opts, visited) {
3467
3476
  if (!store.writeBytes) {
3468
3477
  throw new Error("Installing a node-template requires a PackageStore with writeBytes (binary). This host does not support it.");
3469
3478
  }
3470
- const dir = joinPosix(root, ".prompd", getInstallDirForType("node-template"));
3479
+ const dir = joinPosix(root, installDir, getInstallDirForType("node-template"));
3471
3480
  installedPath = joinPosix(dir, `${slugify(name)}-${version}.pdpkg`);
3472
3481
  await store.writeBytes(installedPath, bytes);
3473
3482
  } else {
3474
- installedPath = resolveInstallDir(root, type, name, version);
3483
+ installedPath = resolveInstallDir(root, installDir, type, name, version);
3475
3484
  const base = normalizePosix(installedPath);
3476
3485
  await store.removeDir?.(installedPath);
3477
3486
  for (const [rel, content] of files) {
@@ -3494,13 +3503,14 @@ async function installInternal(opts, visited) {
3494
3503
  }
3495
3504
  async function uninstallPackage(opts) {
3496
3505
  const { root, store, global } = opts;
3506
+ const installDir = checkInstallDir(opts.installDir);
3497
3507
  if (!store.removeDir) throw new Error("Uninstall requires a PackageStore with removeDir.");
3498
3508
  const parsed = parsePackageReference(opts.ref);
3499
3509
  const name = parsed.name;
3500
3510
  const removed = [];
3501
3511
  for (const type of ["package", "workflow", "skill", "node-template"]) {
3502
3512
  if (type === "node-template") {
3503
- const dir = joinPosix(root, ".prompd", getInstallDirForType("node-template"));
3513
+ const dir = joinPosix(root, installDir, getInstallDirForType("node-template"));
3504
3514
  if (!store.readdir || !store.removeFile || !store.readBytes) continue;
3505
3515
  try {
3506
3516
  for (const entry of await store.readdir(dir)) {
@@ -3518,7 +3528,7 @@ async function uninstallPackage(opts) {
3518
3528
  } catch {
3519
3529
  }
3520
3530
  } else {
3521
- const dir = resolvePackageDir(root, type, name);
3531
+ const dir = resolvePackageDir(root, installDir, type, name);
3522
3532
  await store.removeDir(dir);
3523
3533
  removed.push(dir);
3524
3534
  }
@@ -5084,6 +5094,817 @@ function forkJoinId(file, parallelId) {
5084
5094
  return file.edges.find((e) => members.has(e.source) && e.targetHandle?.startsWith("input-"))?.target;
5085
5095
  }
5086
5096
 
5097
+ // src/lib/expression.ts
5098
+ var BRANDED = /* @__PURE__ */ new WeakSet();
5099
+ var ExpressionError = class _ExpressionError extends Error {
5100
+ constructor(message, construct, position) {
5101
+ super(message);
5102
+ this.name = "ExpressionError";
5103
+ this.construct = construct;
5104
+ this.position = position;
5105
+ if (new.target === _ExpressionError) {
5106
+ BRANDED.add(this);
5107
+ Object.freeze(this);
5108
+ }
5109
+ }
5110
+ };
5111
+ function isOwnExpressionError(e) {
5112
+ return typeof e === "object" && e !== null && BRANDED.has(e);
5113
+ }
5114
+ function ownDataField(o, key) {
5115
+ const d = Object.getOwnPropertyDescriptor(o, key);
5116
+ return d && "value" in d ? d.value : void 0;
5117
+ }
5118
+ function expressionErrorFields(e) {
5119
+ if (e === null || typeof e !== "object") return null;
5120
+ try {
5121
+ if (ownDataField(e, "name") !== "ExpressionError") return null;
5122
+ const construct = ownDataField(e, "construct");
5123
+ const position = ownDataField(e, "position");
5124
+ if (typeof construct !== "string" || typeof position !== "number") return null;
5125
+ const message = ownDataField(e, "message");
5126
+ return { construct, position, message: typeof message === "string" ? message : "" };
5127
+ } catch {
5128
+ return null;
5129
+ }
5130
+ }
5131
+ function ownMessage(e) {
5132
+ if (e === null || typeof e !== "object") return "unknown error";
5133
+ try {
5134
+ const m = ownDataField(e, "message");
5135
+ return typeof m === "string" ? m : "unknown error";
5136
+ } catch {
5137
+ return "unknown error";
5138
+ }
5139
+ }
5140
+ function isExpressionError(e) {
5141
+ return isOwnExpressionError(e) || expressionErrorFields(e) !== null;
5142
+ }
5143
+ var MAX_EXPRESSION_LENGTH = 2e3;
5144
+ var MAX_EXPRESSION_DEPTH = 64;
5145
+ var BLOCKED_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
5146
+ var STRING_METHODS = /* @__PURE__ */ new Set([
5147
+ "includes",
5148
+ "startsWith",
5149
+ "endsWith",
5150
+ "toLowerCase",
5151
+ "toUpperCase",
5152
+ "trim",
5153
+ "indexOf",
5154
+ "slice"
5155
+ ]);
5156
+ var ARRAY_METHODS = /* @__PURE__ */ new Set(["includes", "indexOf", "join", "slice"]);
5157
+ var KEYWORD_CONSTRUCTS = /* @__PURE__ */ new Map([
5158
+ ["new", "'new'"],
5159
+ ["typeof", "'typeof'"],
5160
+ ["void", "'void'"],
5161
+ ["delete", "'delete'"],
5162
+ ["in", "the 'in' operator"],
5163
+ ["instanceof", "'instanceof'"],
5164
+ ["function", "a function expression"],
5165
+ ["class", "a class expression"],
5166
+ ["this", "'this'"],
5167
+ ["await", "'await'"],
5168
+ ["yield", "'yield'"],
5169
+ ["import", "'import'"],
5170
+ ["super", "'super'"],
5171
+ ["let", "a declaration"],
5172
+ ["var", "a declaration"],
5173
+ ["const", "a declaration"],
5174
+ ["return", "a statement"]
5175
+ ]);
5176
+ var ASSIGNMENT_OPS = ["=", "+=", "-=", "*=", "/=", "%=", "**=", "&=", "|=", "^=", "<<=", ">>=", ">>>=", "&&=", "||=", "??="];
5177
+ var OP_CONSTRUCTS = new Map([
5178
+ ...ASSIGNMENT_OPS.map((o) => [o, "assignment"]),
5179
+ ["=>", "an arrow function"],
5180
+ ["++", "increment/decrement"],
5181
+ ["--", "increment/decrement"],
5182
+ ["&", "a bitwise operator"],
5183
+ ["|", "a bitwise operator"],
5184
+ ["^", "a bitwise operator"],
5185
+ ["~", "a bitwise operator"],
5186
+ ["<<", "a bitwise operator"],
5187
+ [">>", "a bitwise operator"],
5188
+ [">>>", "a bitwise operator"],
5189
+ ["**", "the exponent operator"],
5190
+ [",", "the comma operator"],
5191
+ [";", "a statement separator"],
5192
+ ["...", "spread"]
5193
+ ]);
5194
+ var OPS = [
5195
+ ...ASSIGNMENT_OPS,
5196
+ "...",
5197
+ "===",
5198
+ "!==",
5199
+ ">>>",
5200
+ "=>",
5201
+ "**",
5202
+ "?.",
5203
+ "??",
5204
+ "==",
5205
+ "!=",
5206
+ "<=",
5207
+ ">=",
5208
+ "&&",
5209
+ "||",
5210
+ "++",
5211
+ "--",
5212
+ "<<",
5213
+ ">>",
5214
+ "(",
5215
+ ")",
5216
+ "[",
5217
+ "]",
5218
+ "{",
5219
+ "}",
5220
+ ",",
5221
+ ":",
5222
+ ".",
5223
+ "?",
5224
+ "!",
5225
+ "+",
5226
+ "-",
5227
+ "*",
5228
+ "/",
5229
+ "%",
5230
+ "<",
5231
+ ">",
5232
+ "&",
5233
+ "|",
5234
+ "^",
5235
+ "~",
5236
+ ";"
5237
+ ].sort((a, b) => b.length - a.length);
5238
+ function disallowed(construct, position) {
5239
+ return new ExpressionError(`${construct} is not allowed in a workflow expression`, construct, position);
5240
+ }
5241
+ function syntax(message, position) {
5242
+ return new ExpressionError(message, "syntax error", position);
5243
+ }
5244
+ function describeExpressionFailure(kind, label, e) {
5245
+ const f = expressionErrorFields(e);
5246
+ if (!f) return `${kind} on "${label}" has an invalid expression: ${ownMessage(e)}.`;
5247
+ return f.construct === "syntax error" || f.construct === "evaluation error" ? `${kind} on "${label}" has an invalid expression: ${f.message} (position ${f.position}).` : `${kind} on "${label}" can't run: ${f.construct}, which workflow expressions can't do (position ${f.position}).`;
5248
+ }
5249
+ var SIMPLE_ESCAPES = /* @__PURE__ */ new Map([
5250
+ ["n", "\n"],
5251
+ ["t", " "],
5252
+ ["r", "\r"],
5253
+ ["b", "\b"],
5254
+ ["f", "\f"],
5255
+ ["v", "\v"],
5256
+ ["0", "\0"]
5257
+ ]);
5258
+ function readString(src, start) {
5259
+ const q = src[start];
5260
+ let out = "";
5261
+ let i = start + 1;
5262
+ while (i < src.length) {
5263
+ const c = src[i];
5264
+ if (c === q) return [out, i + 1];
5265
+ if (c === "\n") break;
5266
+ if (c === "\\") {
5267
+ const n = src[i + 1];
5268
+ if (n === void 0) break;
5269
+ const simple = SIMPLE_ESCAPES.get(n);
5270
+ if (simple !== void 0) {
5271
+ out += simple;
5272
+ i += 2;
5273
+ continue;
5274
+ }
5275
+ if (n === "x" || n === "u") {
5276
+ const len = n === "x" ? 2 : 4;
5277
+ const hex = src.slice(i + 2, i + 2 + len);
5278
+ if (!new RegExp(`^[0-9a-fA-F]{${len}}$`).test(hex)) throw syntax("invalid escape sequence", i);
5279
+ out += String.fromCharCode(parseInt(hex, 16));
5280
+ i += 2 + len;
5281
+ continue;
5282
+ }
5283
+ out += n;
5284
+ i += 2;
5285
+ continue;
5286
+ }
5287
+ out += c;
5288
+ i++;
5289
+ }
5290
+ throw syntax("unterminated string", start);
5291
+ }
5292
+ function tokenize(src) {
5293
+ const toks = [];
5294
+ let i = 0;
5295
+ while (i < src.length) {
5296
+ const c = src[i];
5297
+ if (/\s/.test(c)) {
5298
+ i++;
5299
+ continue;
5300
+ }
5301
+ if (c === "`") throw disallowed("a template literal", i);
5302
+ if (c === '"' || c === "'") {
5303
+ const [s, next] = readString(src, i);
5304
+ toks.push({ t: "str", v: s, p: i });
5305
+ i = next;
5306
+ continue;
5307
+ }
5308
+ if (/[0-9]/.test(c) || c === "." && /[0-9]/.test(src[i + 1] ?? "")) {
5309
+ const m = /^(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?/.exec(src.slice(i));
5310
+ if (!m) throw syntax("invalid number", i);
5311
+ toks.push({ t: "num", v: Number(m[0]), p: i });
5312
+ i += m[0].length;
5313
+ if (/[A-Za-z_$0-9]/.test(src[i] ?? "")) throw syntax("invalid number", i);
5314
+ continue;
5315
+ }
5316
+ if (/[A-Za-z_$]/.test(c)) {
5317
+ const m = /^[A-Za-z_$][\w$]*/.exec(src.slice(i));
5318
+ const name = m ? m[0] : c;
5319
+ toks.push({ t: "id", v: name, p: i });
5320
+ i += name.length;
5321
+ continue;
5322
+ }
5323
+ const op = OPS.find((o) => src.startsWith(o, i) && !(o === "?." && /[0-9]/.test(src[i + 2] ?? "")));
5324
+ if (!op) throw syntax(`unexpected character '${c}'`, i);
5325
+ toks.push({ t: "op", v: op, p: i });
5326
+ i += op.length;
5327
+ }
5328
+ toks.push({ t: "eof", p: src.length });
5329
+ return toks;
5330
+ }
5331
+ var Parser = class {
5332
+ constructor(toks) {
5333
+ this.toks = toks;
5334
+ this.i = 0;
5335
+ this.depth = 0;
5336
+ }
5337
+ parseAll() {
5338
+ const n = this.expr();
5339
+ const t = this.peek();
5340
+ if (t.t !== "eof") throw this.unexpected(t);
5341
+ return n;
5342
+ }
5343
+ peek() {
5344
+ return this.toks[this.i];
5345
+ }
5346
+ next() {
5347
+ return this.toks[this.i++];
5348
+ }
5349
+ isOp(v) {
5350
+ const t = this.peek();
5351
+ return t.t === "op" && t.v === v;
5352
+ }
5353
+ eatOp(v) {
5354
+ if (this.isOp(v)) {
5355
+ this.i++;
5356
+ return true;
5357
+ }
5358
+ return false;
5359
+ }
5360
+ expectOp(v) {
5361
+ if (!this.eatOp(v)) throw this.unexpected(this.peek());
5362
+ }
5363
+ enter(p) {
5364
+ if (++this.depth > MAX_EXPRESSION_DEPTH) throw disallowed(`nesting deeper than ${MAX_EXPRESSION_DEPTH} levels`, p);
5365
+ }
5366
+ leave() {
5367
+ this.depth--;
5368
+ }
5369
+ unexpected(t) {
5370
+ if (t.t === "eof") return syntax("unexpected end of expression", t.p);
5371
+ if (t.t === "id") {
5372
+ const kw = KEYWORD_CONSTRUCTS.get(t.v);
5373
+ return kw ? disallowed(kw, t.p) : syntax(`unexpected '${t.v}'`, t.p);
5374
+ }
5375
+ if (t.t !== "op") return syntax("unexpected value", t.p);
5376
+ const c = OP_CONSTRUCTS.get(t.v);
5377
+ return c ? disallowed(c, t.p) : syntax(`unexpected '${t.v}'`, t.p);
5378
+ }
5379
+ expr() {
5380
+ this.enter(this.peek().p);
5381
+ try {
5382
+ return this.conditional();
5383
+ } finally {
5384
+ this.leave();
5385
+ }
5386
+ }
5387
+ conditional() {
5388
+ const test = this.nullish();
5389
+ if (!this.eatOp("?")) return test;
5390
+ const yes = this.expr();
5391
+ this.expectOp(":");
5392
+ const no = this.expr();
5393
+ return { k: "cond", test, yes, no };
5394
+ }
5395
+ binaryLevel(ops, nextLevel) {
5396
+ let l = nextLevel();
5397
+ for (; ; ) {
5398
+ const t = this.peek();
5399
+ if (t.t !== "op" || !ops.includes(t.v)) return l;
5400
+ this.i++;
5401
+ l = { k: "bin", op: t.v, l, r: nextLevel(), p: t.p };
5402
+ }
5403
+ }
5404
+ nullish() {
5405
+ return this.binaryLevel(["??"], () => this.or());
5406
+ }
5407
+ or() {
5408
+ return this.binaryLevel(["||"], () => this.and());
5409
+ }
5410
+ and() {
5411
+ return this.binaryLevel(["&&"], () => this.equality());
5412
+ }
5413
+ equality() {
5414
+ return this.binaryLevel(["==", "!=", "===", "!=="], () => this.relational());
5415
+ }
5416
+ relational() {
5417
+ return this.binaryLevel(["<", "<=", ">", ">="], () => this.additive());
5418
+ }
5419
+ additive() {
5420
+ return this.binaryLevel(["+", "-"], () => this.multiplicative());
5421
+ }
5422
+ multiplicative() {
5423
+ return this.binaryLevel(["*", "/", "%"], () => this.unary());
5424
+ }
5425
+ unary() {
5426
+ const t = this.peek();
5427
+ if (t.t === "op" && (t.v === "!" || t.v === "-" || t.v === "+")) {
5428
+ this.i++;
5429
+ this.enter(t.p);
5430
+ try {
5431
+ return { k: "unary", op: t.v, arg: this.unary(), p: t.p };
5432
+ } finally {
5433
+ this.leave();
5434
+ }
5435
+ }
5436
+ if (t.t === "op" && (t.v === "++" || t.v === "--" || t.v === "~")) throw this.unexpected(t);
5437
+ return this.postfix();
5438
+ }
5439
+ postfix() {
5440
+ let n = this.primary();
5441
+ for (; ; ) {
5442
+ const t = this.peek();
5443
+ if (t.t !== "op") return n;
5444
+ if (t.v === "." || t.v === "?.") {
5445
+ this.i++;
5446
+ const optional = t.v === "?.";
5447
+ if (optional && this.isOp("(")) throw disallowed("an optional call", t.p);
5448
+ if (optional && this.eatOp("[")) {
5449
+ const prop = this.computedKey(t.p);
5450
+ n = { k: "member", obj: n, prop, optional: true, p: t.p };
5451
+ continue;
5452
+ }
5453
+ const name = this.next();
5454
+ if (name.t !== "id") throw syntax("expected a property name", name.p);
5455
+ if (BLOCKED_KEYS.has(name.v)) throw disallowed(`access to ${name.v}`, name.p);
5456
+ n = { k: "member", obj: n, prop: name.v, optional, p: name.p };
5457
+ continue;
5458
+ }
5459
+ if (t.v === "[") {
5460
+ this.i++;
5461
+ n = { k: "member", obj: n, prop: this.computedKey(t.p), optional: false, p: t.p };
5462
+ continue;
5463
+ }
5464
+ if (t.v === "(") {
5465
+ if (n.k === "member" && typeof n.prop === "string" && !n.paren) {
5466
+ if (!STRING_METHODS.has(n.prop) && !ARRAY_METHODS.has(n.prop)) throw disallowed(`call to ${n.prop}`, t.p);
5467
+ this.i++;
5468
+ n = { k: "call", recv: n.obj, name: n.prop, args: this.args(), optional: n.optional, p: t.p };
5469
+ continue;
5470
+ }
5471
+ if (n.k === "id") throw disallowed(`call to ${n.name}`, t.p);
5472
+ if (n.k === "member" && typeof n.prop !== "string" && !n.paren) throw disallowed("a computed method call", t.p);
5473
+ throw disallowed("a function call", t.p);
5474
+ }
5475
+ if (t.v === "++" || t.v === "--") throw this.unexpected(t);
5476
+ return n;
5477
+ }
5478
+ }
5479
+ /** `[expr]` after `[` or `?.[`; a literal blocked key is rejected here, a computed one at evaluation. */
5480
+ computedKey(p) {
5481
+ const prop = this.expr();
5482
+ this.expectOp("]");
5483
+ if (prop.k === "lit" && typeof prop.v === "string" && BLOCKED_KEYS.has(prop.v)) throw disallowed(`access to ${prop.v}`, p);
5484
+ return prop;
5485
+ }
5486
+ args() {
5487
+ const out = [];
5488
+ if (this.eatOp(")")) return out;
5489
+ for (; ; ) {
5490
+ if (this.isOp("...")) throw disallowed("spread", this.peek().p);
5491
+ out.push(this.expr());
5492
+ if (this.eatOp(")")) return out;
5493
+ this.expectOp(",");
5494
+ }
5495
+ }
5496
+ primary() {
5497
+ const t = this.next();
5498
+ if (t.t === "num" || t.t === "str") return { k: "lit", v: t.v };
5499
+ if (t.t === "id") {
5500
+ if (t.v === "true") return { k: "lit", v: true };
5501
+ if (t.v === "false") return { k: "lit", v: false };
5502
+ if (t.v === "null") return { k: "lit", v: null };
5503
+ if (t.v === "undefined") return { k: "lit", v: void 0 };
5504
+ const kw = KEYWORD_CONSTRUCTS.get(t.v);
5505
+ if (kw) throw disallowed(kw, t.p);
5506
+ if (this.isOp("=>")) throw disallowed("an arrow function", this.peek().p);
5507
+ return { k: "id", name: t.v, p: t.p };
5508
+ }
5509
+ if (t.t === "eof") throw syntax("unexpected end of expression", t.p);
5510
+ if (t.t === "op") {
5511
+ if (t.v === "(") {
5512
+ if (this.isOp(")")) throw disallowed("an arrow function", t.p);
5513
+ const inner = this.expr();
5514
+ this.expectOp(")");
5515
+ if (this.isOp("=>")) throw disallowed("an arrow function", this.peek().p);
5516
+ return inner.k === "member" || inner.k === "call" ? { ...inner, paren: true } : inner;
5517
+ }
5518
+ if (t.v === "[") {
5519
+ const items = [];
5520
+ if (this.eatOp("]")) return { k: "arr", items };
5521
+ for (; ; ) {
5522
+ if (this.isOp("...")) throw disallowed("spread", this.peek().p);
5523
+ items.push(this.expr());
5524
+ if (this.eatOp("]")) return { k: "arr", items };
5525
+ this.expectOp(",");
5526
+ }
5527
+ }
5528
+ if (t.v === "{") return this.objectLiteral();
5529
+ if (t.v === "/") throw disallowed("a regex literal", t.p);
5530
+ }
5531
+ throw this.unexpected(t);
5532
+ }
5533
+ objectLiteral() {
5534
+ const props = [];
5535
+ if (this.eatOp("}")) return { k: "obj", props };
5536
+ for (; ; ) {
5537
+ const k = this.next();
5538
+ if (k.t === "op" && k.v === "...") throw disallowed("spread", k.p);
5539
+ if (k.t === "op" && k.v === "[") throw disallowed("a computed key", k.p);
5540
+ if (k.t !== "id" && k.t !== "str") throw syntax("expected a property name", k.p);
5541
+ if (BLOCKED_KEYS.has(k.v)) throw disallowed(`access to ${k.v}`, k.p);
5542
+ this.expectOp(":");
5543
+ props.push({ key: k.v, value: this.expr() });
5544
+ if (this.eatOp("}")) return { k: "obj", props };
5545
+ this.expectOp(",");
5546
+ }
5547
+ }
5548
+ };
5549
+ function stripWrapper(expr) {
5550
+ const t = expr.trim();
5551
+ return t.startsWith("{{") && t.endsWith("}}") ? t.slice(2, -2).trim() : t;
5552
+ }
5553
+ function parseExpression(expr) {
5554
+ const src = stripWrapper(expr);
5555
+ if (src.length > MAX_EXPRESSION_LENGTH) {
5556
+ throw disallowed(`an expression longer than ${MAX_EXPRESSION_LENGTH} characters`, MAX_EXPRESSION_LENGTH);
5557
+ }
5558
+ if (!src) throw syntax("empty expression", 0);
5559
+ return new Parser(tokenize(src)).parseAll();
5560
+ }
5561
+ function validateExpression(expr) {
5562
+ try {
5563
+ parseExpression(expr);
5564
+ return null;
5565
+ } catch (e) {
5566
+ if (isExpressionError(e)) return e;
5567
+ throw e;
5568
+ }
5569
+ }
5570
+ var SHORT = /* @__PURE__ */ Symbol("optional-chain-short-circuit");
5571
+ function ownData(obj, key) {
5572
+ const d = Object.getOwnPropertyDescriptor(obj, key);
5573
+ if (!d || !("value" in d)) return void 0;
5574
+ return typeof d.value === "function" ? void 0 : d.value;
5575
+ }
5576
+ function isCanonicalIndex(key) {
5577
+ const n = Number(key);
5578
+ return Number.isInteger(n) && n >= 0 && String(n) === key;
5579
+ }
5580
+ function isPlainObject(o) {
5581
+ const proto = Object.getPrototypeOf(o);
5582
+ return proto === Object.prototype || proto === null;
5583
+ }
5584
+ function isPlainArray(o) {
5585
+ return Array.isArray(o) && Object.getPrototypeOf(o) === Array.prototype;
5586
+ }
5587
+ function dataValue(v) {
5588
+ if (typeof v === "function") return void 0;
5589
+ if (v === null || typeof v !== "object") return v;
5590
+ return isPlainArray(v) || isPlainObject(v) ? v : void 0;
5591
+ }
5592
+ function readProp(obj, key, p, options) {
5593
+ if (BLOCKED_KEYS.has(key)) throw disallowed(`access to ${key}`, p);
5594
+ return dataValue(readOwnMember(obj, key, options));
5595
+ }
5596
+ var MAX_JSON_NAV_LENGTH = 1e6;
5597
+ function stripCodeFence(s) {
5598
+ const open = s.indexOf("```");
5599
+ if (open === -1) return s;
5600
+ const close = s.indexOf("```", open + 3);
5601
+ if (close === -1) return s;
5602
+ const inner = s.slice(open + 3, close);
5603
+ return inner.startsWith("json") ? inner.slice(4) : inner;
5604
+ }
5605
+ function parseJsonFromString(s) {
5606
+ if (s.length > MAX_JSON_NAV_LENGTH) return void 0;
5607
+ const text = stripCodeFence(s).trim();
5608
+ if (!text) return void 0;
5609
+ try {
5610
+ return JSON.parse(text);
5611
+ } catch {
5612
+ return void 0;
5613
+ }
5614
+ }
5615
+ function readOwnMember(obj, key, options) {
5616
+ if (typeof obj === "string") {
5617
+ if (key === "length") return obj.length;
5618
+ if (isCanonicalIndex(key)) {
5619
+ return Number(key) < obj.length ? obj.charAt(Number(key)) : void 0;
5620
+ }
5621
+ if (options?.parseJsonStrings) {
5622
+ const parsed = parseJsonFromString(obj);
5623
+ if (parsed !== null && typeof parsed === "object" && (isPlainArray(parsed) || isPlainObject(parsed))) {
5624
+ return readOwnMember(parsed, key, options);
5625
+ }
5626
+ }
5627
+ return void 0;
5628
+ }
5629
+ if (obj === null || typeof obj !== "object") return void 0;
5630
+ if (isPlainArray(obj)) return key === "length" ? ownIndexLength(obj) : ownData(obj, key);
5631
+ if (isPlainObject(obj)) return ownData(obj, key);
5632
+ return void 0;
5633
+ }
5634
+ function describeType(v) {
5635
+ if (v === null) return "null";
5636
+ if (v === void 0) return "undefined";
5637
+ if (Array.isArray(v)) return "an array";
5638
+ const t = typeof v;
5639
+ return t === "object" ? "an object" : `a ${t}`;
5640
+ }
5641
+ function prim(v, p, what) {
5642
+ if (v === null) return v;
5643
+ const t = typeof v;
5644
+ if (t === "object" || t === "function" || t === "symbol") {
5645
+ throw new ExpressionError(`${what} needs a plain value, not ${describeType(v)}`, "evaluation error", p);
5646
+ }
5647
+ return v;
5648
+ }
5649
+ function propKey(v, p) {
5650
+ const pv = prim(v, p, "a computed property key");
5651
+ return typeof pv === "string" ? pv : String(pv);
5652
+ }
5653
+ function ownIndexLength(a) {
5654
+ const d = Object.getOwnPropertyDescriptor(a, "length");
5655
+ if (!d || !("value" in d)) return 0;
5656
+ const v = d.value;
5657
+ return typeof v === "number" && Number.isSafeInteger(v) && v >= 0 ? v : 0;
5658
+ }
5659
+ var MAX_ARRAY_SCAN = 1e6;
5660
+ function scanLength(a, name, p) {
5661
+ const len = ownIndexLength(a);
5662
+ if (len > MAX_ARRAY_SCAN) {
5663
+ throw new ExpressionError(
5664
+ `${name} on an array longer than ${MAX_ARRAY_SCAN} elements is not allowed in a workflow expression`,
5665
+ "evaluation error",
5666
+ p
5667
+ );
5668
+ }
5669
+ return len;
5670
+ }
5671
+ function ownIndexDescriptor(a, i) {
5672
+ return Object.getOwnPropertyDescriptor(a, String(i));
5673
+ }
5674
+ function ownIndex(a, i) {
5675
+ const d = ownIndexDescriptor(a, i);
5676
+ return d && "value" in d ? d.value : void 0;
5677
+ }
5678
+ function toIntegerOrInfinity(v) {
5679
+ const n = Number(v);
5680
+ if (Number.isNaN(n) || n === 0) return 0;
5681
+ if (!Number.isFinite(n)) return n;
5682
+ const t = Math.trunc(n);
5683
+ return t === 0 ? 0 : t;
5684
+ }
5685
+ function sameValueZero(x, y) {
5686
+ return x === y || typeof x === "number" && typeof y === "number" && Number.isNaN(x) && Number.isNaN(y);
5687
+ }
5688
+ function arraySlice(a, args, p) {
5689
+ const startArg = args.length > 0 ? prim(args[0], p, "a slice argument") : void 0;
5690
+ const endArg = args.length > 1 ? prim(args[1], p, "a slice argument") : void 0;
5691
+ const len = scanLength(a, "slice", p);
5692
+ const relStart = startArg === void 0 ? 0 : toIntegerOrInfinity(startArg);
5693
+ const k = relStart < 0 ? Math.max(len + relStart, 0) : Math.min(relStart, len);
5694
+ const relEnd = endArg === void 0 ? len : toIntegerOrInfinity(endArg);
5695
+ const final = relEnd < 0 ? Math.max(len + relEnd, 0) : Math.min(relEnd, len);
5696
+ const count = Math.max(final - k, 0);
5697
+ const out = [];
5698
+ for (let j = 0; j < count; j++) out.push(dataValue(ownIndex(a, k + j)));
5699
+ return out;
5700
+ }
5701
+ function arrayJoin(a, args, p) {
5702
+ const sepArg = args.length > 0 ? prim(args[0], p, "the join separator") : void 0;
5703
+ const sep = sepArg === void 0 ? "," : String(sepArg);
5704
+ const len = scanLength(a, "join", p);
5705
+ const parts = [];
5706
+ for (let i = 0; i < len; i++) {
5707
+ const e = ownIndex(a, i);
5708
+ if (e === void 0 || e === null) {
5709
+ parts.push("");
5710
+ continue;
5711
+ }
5712
+ parts.push(String(prim(e, p, "an array element passed to join")));
5713
+ }
5714
+ return parts.join(sep);
5715
+ }
5716
+ function arrayIncludes(a, args, p) {
5717
+ const search = args[0];
5718
+ const fromArg = args.length > 1 ? prim(args[1], p, "a fromIndex argument") : void 0;
5719
+ const len = scanLength(a, "includes", p);
5720
+ const rel = fromArg === void 0 ? 0 : toIntegerOrInfinity(fromArg);
5721
+ const from = rel < 0 ? Math.max(len + rel, 0) : rel;
5722
+ for (let i = from; i < len; i++) {
5723
+ if (sameValueZero(ownIndex(a, i), search)) return true;
5724
+ }
5725
+ return false;
5726
+ }
5727
+ function arrayIndexOf(a, args, p) {
5728
+ const search = args[0];
5729
+ const fromArg = args.length > 1 ? prim(args[1], p, "a fromIndex argument") : void 0;
5730
+ const len = scanLength(a, "indexOf", p);
5731
+ const rel = fromArg === void 0 ? 0 : toIntegerOrInfinity(fromArg);
5732
+ const from = rel < 0 ? Math.max(len + rel, 0) : rel;
5733
+ for (let i = from; i < len; i++) {
5734
+ const d = ownIndexDescriptor(a, i);
5735
+ if (d === void 0) continue;
5736
+ if (("value" in d ? d.value : void 0) === search) return i;
5737
+ }
5738
+ return -1;
5739
+ }
5740
+ function looseEq(l, r) {
5741
+ const lRef = l !== null && (typeof l === "object" || typeof l === "function");
5742
+ const rRef = r !== null && (typeof r === "object" || typeof r === "function");
5743
+ if (lRef || rRef) return l === r;
5744
+ return l == r;
5745
+ }
5746
+ function callMethod(recv, name, args, p) {
5747
+ if (typeof recv === "string" && STRING_METHODS.has(name)) {
5748
+ const fn = Reflect.get(String.prototype, name);
5749
+ if (typeof fn === "function") {
5750
+ const primArgs = args.map((a) => prim(a, p, `an argument to ${name}`));
5751
+ return Reflect.apply(fn, recv, primArgs);
5752
+ }
5753
+ }
5754
+ if (Array.isArray(recv) && Object.getPrototypeOf(recv) === Array.prototype && ARRAY_METHODS.has(name)) {
5755
+ if (name === "join") return arrayJoin(recv, args, p);
5756
+ if (name === "slice") return arraySlice(recv, args, p);
5757
+ if (name === "includes") return arrayIncludes(recv, args, p);
5758
+ if (name === "indexOf") return arrayIndexOf(recv, args, p);
5759
+ }
5760
+ const msg = `call to ${name} on ${describeType(recv)}`;
5761
+ if (STRING_METHODS.has(name) || ARRAY_METHODS.has(name)) {
5762
+ throw new ExpressionError(`${msg} is not allowed in a workflow expression`, "evaluation error", p);
5763
+ }
5764
+ throw disallowed(msg, p);
5765
+ }
5766
+ function toNum(v) {
5767
+ return typeof v === "number" ? v : Number(v);
5768
+ }
5769
+ function missingOperand(p) {
5770
+ return new ExpressionError(
5771
+ "arithmetic on a missing value (a hyphenated name like a-b is subtraction; read it as nodes['a-b'])",
5772
+ "evaluation error",
5773
+ p
5774
+ );
5775
+ }
5776
+ function arithOperand(v, p, what) {
5777
+ const pv = prim(v, p, what);
5778
+ if (pv === void 0) throw missingOperand(p);
5779
+ return pv;
5780
+ }
5781
+ var Evaluator = class {
5782
+ constructor(scope, options = {}) {
5783
+ this.scope = scope;
5784
+ this.options = options;
5785
+ }
5786
+ run(n) {
5787
+ return this.val(n);
5788
+ }
5789
+ val(n) {
5790
+ const v = this.ev(n);
5791
+ return v === SHORT ? void 0 : v;
5792
+ }
5793
+ /** The object side of a member or call. Continues an optional chain (SHORT
5794
+ * propagates) unless the object was parenthesized, which ends the chain. */
5795
+ chain(n) {
5796
+ return (n.k === "member" || n.k === "call") && !n.paren ? this.ev(n) : this.val(n);
5797
+ }
5798
+ ev(n) {
5799
+ switch (n.k) {
5800
+ case "lit":
5801
+ return n.v;
5802
+ case "id":
5803
+ return dataValue(ownData(this.scope, n.name));
5804
+ case "arr":
5805
+ return n.items.map((x) => this.val(x));
5806
+ case "obj": {
5807
+ const o = {};
5808
+ for (const pr of n.props) o[pr.key] = this.val(pr.value);
5809
+ return o;
5810
+ }
5811
+ case "member": {
5812
+ const o = this.chain(n.obj);
5813
+ if (o === SHORT) return SHORT;
5814
+ if (n.optional && (o === null || o === void 0)) return SHORT;
5815
+ const key = typeof n.prop === "string" ? n.prop : propKey(this.val(n.prop), n.p);
5816
+ return readProp(o, key, n.p, this.options);
5817
+ }
5818
+ case "call": {
5819
+ const r = this.chain(n.recv);
5820
+ if (r === SHORT) return SHORT;
5821
+ if (n.optional && (r === null || r === void 0)) return SHORT;
5822
+ return callMethod(r, n.name, n.args.map((a) => this.val(a)), n.p);
5823
+ }
5824
+ case "unary": {
5825
+ const v = this.val(n.arg);
5826
+ if (n.op === "!") return !v;
5827
+ const pv = prim(v, n.p, `unary '${n.op}'`);
5828
+ return n.op === "-" ? -toNum(pv) : toNum(pv);
5829
+ }
5830
+ case "cond":
5831
+ return this.val(n.test) ? this.val(n.yes) : this.val(n.no);
5832
+ case "bin":
5833
+ return this.bin(n);
5834
+ }
5835
+ }
5836
+ bin(n) {
5837
+ if (n.op === "&&") {
5838
+ const l2 = this.val(n.l);
5839
+ return l2 ? this.val(n.r) : l2;
5840
+ }
5841
+ if (n.op === "||") {
5842
+ const l2 = this.val(n.l);
5843
+ return l2 ? l2 : this.val(n.r);
5844
+ }
5845
+ if (n.op === "??") {
5846
+ const l2 = this.val(n.l);
5847
+ return l2 === null || l2 === void 0 ? this.val(n.r) : l2;
5848
+ }
5849
+ const l = this.val(n.l);
5850
+ const r = this.val(n.r);
5851
+ switch (n.op) {
5852
+ case "+": {
5853
+ const lp = prim(l, n.p, "'+'");
5854
+ const rp = prim(r, n.p, "'+'");
5855
+ if (typeof lp === "string" || typeof rp === "string") return String(lp) + String(rp);
5856
+ if (lp === void 0 || rp === void 0) throw missingOperand(n.p);
5857
+ return toNum(lp) + toNum(rp);
5858
+ }
5859
+ case "-":
5860
+ return toNum(arithOperand(l, n.p, "'-'")) - toNum(arithOperand(r, n.p, "'-'"));
5861
+ case "*":
5862
+ return toNum(arithOperand(l, n.p, "'*'")) * toNum(arithOperand(r, n.p, "'*'"));
5863
+ case "/":
5864
+ return toNum(arithOperand(l, n.p, "'/'")) / toNum(arithOperand(r, n.p, "'/'"));
5865
+ case "%":
5866
+ return toNum(arithOperand(l, n.p, "'%'")) % toNum(arithOperand(r, n.p, "'%'"));
5867
+ case "==":
5868
+ return looseEq(l, r);
5869
+ case "!=":
5870
+ return !looseEq(l, r);
5871
+ case "===":
5872
+ return l === r;
5873
+ case "!==":
5874
+ return l !== r;
5875
+ case "<":
5876
+ return prim(l, n.p, "'<'") < prim(r, n.p, "'<'");
5877
+ case "<=":
5878
+ return prim(l, n.p, "'<='") <= prim(r, n.p, "'<='");
5879
+ case ">":
5880
+ return prim(l, n.p, "'>'") > prim(r, n.p, "'>'");
5881
+ case ">=":
5882
+ return prim(l, n.p, "'>='") >= prim(r, n.p, "'>='");
5883
+ default:
5884
+ throw syntax(`unknown operator '${n.op}'`, 0);
5885
+ }
5886
+ }
5887
+ };
5888
+ function thrownDetail(e) {
5889
+ if (e === null || typeof e !== "object" && typeof e !== "function") return String(e);
5890
+ const d = Object.getOwnPropertyDescriptor(e, "message");
5891
+ return d && "value" in d && typeof d.value === "string" ? d.value : "unknown error";
5892
+ }
5893
+ function evaluateExpression(expr, scope, options) {
5894
+ const ast = parseExpression(expr);
5895
+ try {
5896
+ return new Evaluator(scope, options).run(ast);
5897
+ } catch (e) {
5898
+ if (isOwnExpressionError(e)) throw e;
5899
+ let detail = "unknown error";
5900
+ try {
5901
+ detail = thrownDetail(e);
5902
+ } catch {
5903
+ }
5904
+ throw new ExpressionError(`the expression could not be evaluated: ${detail}`, "evaluation error", 0);
5905
+ }
5906
+ }
5907
+
5087
5908
  exports.AnthropicFormatter = AnthropicFormatter;
5088
5909
  exports.BUILTIN_COMMAND_EXECUTABLES = BUILTIN_COMMAND_EXECUTABLES;
5089
5910
  exports.CODE_EXTENSIONS = CODE_EXTENSIONS;
@@ -5100,8 +5921,13 @@ exports.DOCKABLE_NODE_TYPES = DOCKABLE_NODE_TYPES;
5100
5921
  exports.DependencyResolutionStage = DependencyResolutionStage;
5101
5922
  exports.EXTENSION_TO_LANGUAGE = EXTENSION_TO_LANGUAGE;
5102
5923
  exports.EXTENSION_TO_LANGUAGE_ALIASES = EXTENSION_TO_LANGUAGE_ALIASES;
5924
+ exports.ExpressionError = ExpressionError;
5103
5925
  exports.HybridFileSystem = HybridFileSystem;
5104
5926
  exports.LexicalAnalysisStage = LexicalAnalysisStage;
5927
+ exports.MAX_ARRAY_SCAN = MAX_ARRAY_SCAN;
5928
+ exports.MAX_EXPRESSION_DEPTH = MAX_EXPRESSION_DEPTH;
5929
+ exports.MAX_EXPRESSION_LENGTH = MAX_EXPRESSION_LENGTH;
5930
+ exports.MAX_JSON_NAV_LENGTH = MAX_JSON_NAV_LENGTH;
5105
5931
  exports.MEMORY_OPERATIONS_BY_MODE = MEMORY_OPERATIONS_BY_MODE;
5106
5932
  exports.MarkdownFormatter = MarkdownFormatter;
5107
5933
  exports.MemoryFileSystem = MemoryFileSystem;
@@ -5127,7 +5953,9 @@ exports.createCoreStages = createCoreStages;
5127
5953
  exports.createEmptyWorkflow = createEmptyWorkflow;
5128
5954
  exports.createPrompdEnvironment = createPrompdEnvironment;
5129
5955
  exports.createWorkflowNode = createWorkflowNode;
5956
+ exports.describeExpressionFailure = describeExpressionFailure;
5130
5957
  exports.dirnamePosix = dirnamePosix;
5958
+ exports.evaluateExpression = evaluateExpression;
5131
5959
  exports.extname = extname;
5132
5960
  exports.extractPdpkg = extractPdpkg;
5133
5961
  exports.forkJoinId = forkJoinId;
@@ -5138,6 +5966,7 @@ exports.getLanguageAliasesForExtension = getLanguageAliasesForExtension;
5138
5966
  exports.getLanguageForExtension = getLanguageForExtension;
5139
5967
  exports.installPackage = installPackage;
5140
5968
  exports.isAbsolutePosix = isAbsolutePosix;
5969
+ exports.isExpressionError = isExpressionError;
5141
5970
  exports.isPrompdFile = isPrompdFile;
5142
5971
  exports.isValidPackageReference = isValidPackageReference;
5143
5972
  exports.isValidPackageType = isValidPackageType;
@@ -5155,6 +5984,7 @@ exports.serializeWorkflow = serializeWorkflow;
5155
5984
  exports.stripFilePath = stripFilePath;
5156
5985
  exports.traceForkBranches = traceForkBranches;
5157
5986
  exports.uninstallPackage = uninstallPackage;
5987
+ exports.validateExpression = validateExpression;
5158
5988
  exports.validateWorkflow = validateWorkflow;
5159
5989
  exports.validateWorkflowQuick = validateWorkflowQuick;
5160
5990
  //# sourceMappingURL=index.cjs.map