@valbuild/server 0.65.2 → 0.67.0

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.
@@ -38,8 +38,11 @@ export declare function deepValidateExpression(value: ts.Expression): result.Res
38
38
  export declare function evaluateExpression(value: ts.Expression): result.Result<JSONValue, ValSyntaxErrorTree>;
39
39
  export declare function findObjectPropertyAssignment(value: ts.ObjectLiteralExpression, key: string): result.Result<LiteralPropertyAssignment | undefined, ValSyntaxErrorTree>;
40
40
  export declare function isValFileMethodCall(node: ts.Expression): node is ts.CallExpression;
41
+ export declare function isValImageMethodCall(node: ts.Expression): node is ts.CallExpression;
41
42
  export declare function findValFileNodeArg(node: ts.CallExpression): result.Result<ts.StringLiteral, ValSyntaxErrorTree>;
43
+ export declare function findValImageNodeArg(node: ts.CallExpression): result.Result<ts.StringLiteral, ValSyntaxErrorTree>;
42
44
  export declare function findValFileMetadataArg(node: ts.CallExpression): result.Result<ts.ObjectLiteralExpression | undefined, ValSyntaxErrorTree>;
45
+ export declare function findValImageMetadataArg(node: ts.CallExpression): result.Result<ts.ObjectLiteralExpression | undefined, ValSyntaxErrorTree>;
43
46
  /**
44
47
  * Given a list of expressions, validates that all the expressions are not
45
48
  * spread elements. In other words, it ensures that the expressions are the
@@ -95,7 +95,7 @@ function validateObjectProperties(nodes) {
95
95
  * validating its children.
96
96
  */
97
97
  function shallowValidateExpression(value) {
98
- return ts__default["default"].isStringLiteralLike(value) || ts__default["default"].isNumericLiteral(value) || value.kind === ts__default["default"].SyntaxKind.TrueKeyword || value.kind === ts__default["default"].SyntaxKind.FalseKeyword || value.kind === ts__default["default"].SyntaxKind.NullKeyword || ts__default["default"].isArrayLiteralExpression(value) || ts__default["default"].isObjectLiteralExpression(value) || isValFileMethodCall(value) ? undefined : new ValSyntaxError("Expression must be a literal or call c.file", value);
98
+ return ts__default["default"].isStringLiteralLike(value) || ts__default["default"].isNumericLiteral(value) || value.kind === ts__default["default"].SyntaxKind.TrueKeyword || value.kind === ts__default["default"].SyntaxKind.FalseKeyword || value.kind === ts__default["default"].SyntaxKind.NullKeyword || ts__default["default"].isArrayLiteralExpression(value) || ts__default["default"].isObjectLiteralExpression(value) || isValFileMethodCall(value) || isValImageMethodCall(value) ? undefined : new ValSyntaxError("Expression must be a literal or call c.file", value);
99
99
  }
100
100
 
101
101
  /**
@@ -136,6 +136,23 @@ function evaluateExpression(value) {
136
136
  });
137
137
  }
138
138
  }));
139
+ } else if (isValImageMethodCall(value)) {
140
+ return fp.pipe(findValImageNodeArg(value), fp.result.flatMap(ref => {
141
+ if (value.arguments.length === 2) {
142
+ return fp.pipe(evaluateExpression(value.arguments[1]), fp.result.map(metadata => ({
143
+ [core.FILE_REF_PROP]: ref.text,
144
+ _type: "file",
145
+ [core.FILE_REF_SUBTYPE_TAG]: "image",
146
+ metadata
147
+ })));
148
+ } else {
149
+ return fp.result.ok({
150
+ [core.FILE_REF_PROP]: ref.text,
151
+ _type: "file",
152
+ [core.FILE_REF_SUBTYPE_TAG]: "image"
153
+ });
154
+ }
155
+ }));
139
156
  } else {
140
157
  return fp.result.err(new ValSyntaxError("Expression must be a literal or call c.file", value));
141
158
  }
@@ -154,6 +171,9 @@ function findObjectPropertyAssignment(value, key) {
154
171
  function isValFileMethodCall(node) {
155
172
  return ts__default["default"].isCallExpression(node) && ts__default["default"].isPropertyAccessExpression(node.expression) && ts__default["default"].isIdentifier(node.expression.expression) && node.expression.expression.text === "c" && node.expression.name.text === "file";
156
173
  }
174
+ function isValImageMethodCall(node) {
175
+ return ts__default["default"].isCallExpression(node) && ts__default["default"].isPropertyAccessExpression(node.expression) && ts__default["default"].isIdentifier(node.expression.expression) && node.expression.expression.text === "c" && node.expression.name.text === "image";
176
+ }
157
177
  function findValFileNodeArg(node) {
158
178
  if (node.arguments.length === 0) {
159
179
  return fp.result.err(new ValSyntaxError(`Invalid c.file() call: missing ref argument`, node));
@@ -165,6 +185,17 @@ function findValFileNodeArg(node) {
165
185
  const refNode = node.arguments[0];
166
186
  return fp.result.ok(refNode);
167
187
  }
188
+ function findValImageNodeArg(node) {
189
+ if (node.arguments.length === 0) {
190
+ return fp.result.err(new ValSyntaxError(`Invalid c.image() call: missing ref argument`, node));
191
+ } else if (node.arguments.length > 2) {
192
+ return fp.result.err(new ValSyntaxError(`Invalid c.image() call: too many arguments ${node.arguments.length}}`, node));
193
+ } else if (!ts__default["default"].isStringLiteral(node.arguments[0])) {
194
+ return fp.result.err(new ValSyntaxError(`Invalid c.image() call: ref must be a string literal`, node));
195
+ }
196
+ const refNode = node.arguments[0];
197
+ return fp.result.ok(refNode);
198
+ }
168
199
  function findValFileMetadataArg(node) {
169
200
  if (node.arguments.length === 0) {
170
201
  return fp.result.err(new ValSyntaxError(`Invalid c.file() call: missing ref argument`, node));
@@ -178,6 +209,19 @@ function findValFileMetadataArg(node) {
178
209
  }
179
210
  return fp.result.ok(undefined);
180
211
  }
212
+ function findValImageMetadataArg(node) {
213
+ if (node.arguments.length === 0) {
214
+ return fp.result.err(new ValSyntaxError(`Invalid c.image() call: missing ref argument`, node));
215
+ } else if (node.arguments.length > 2) {
216
+ return fp.result.err(new ValSyntaxError(`Invalid c.image() call: too many arguments ${node.arguments.length}}`, node));
217
+ } else if (node.arguments.length === 2) {
218
+ if (!ts__default["default"].isObjectLiteralExpression(node.arguments[1])) {
219
+ return fp.result.err(new ValSyntaxError(`Invalid c.image() call: metadata must be a object literal`, node));
220
+ }
221
+ return fp.result.ok(node.arguments[1]);
222
+ }
223
+ return fp.result.ok(undefined);
224
+ }
181
225
 
182
226
  /**
183
227
  * Given a list of expressions, validates that all the expressions are not
@@ -272,24 +316,31 @@ function createValFileReference(value) {
272
316
  }
273
317
  return ts__default["default"].factory.createCallExpression(ts__default["default"].factory.createPropertyAccessExpression(ts__default["default"].factory.createIdentifier("c"), ts__default["default"].factory.createIdentifier("file")), undefined, args);
274
318
  }
275
- function createValRichTextImage(value) {
319
+ function createValImageReference(value) {
276
320
  const args = [ts__default["default"].factory.createStringLiteral(value[core.FILE_REF_PROP])];
277
321
  if (value.metadata) {
278
322
  args.push(toExpression(value.metadata));
279
323
  }
280
- return ts__default["default"].factory.createCallExpression(ts__default["default"].factory.createPropertyAccessExpression(ts__default["default"].factory.createPropertyAccessExpression(ts__default["default"].factory.createIdentifier("c"), "rt"), ts__default["default"].factory.createIdentifier("image")), undefined, args);
281
- }
282
- function createValLink(value) {
283
- const args = [ts__default["default"].factory.createStringLiteral(value.children[0]), toExpression({
284
- href: value.href
285
- })];
286
- return ts__default["default"].factory.createCallExpression(ts__default["default"].factory.createPropertyAccessExpression(ts__default["default"].factory.createPropertyAccessExpression(ts__default["default"].factory.createIdentifier("c"), "rt"), ts__default["default"].factory.createIdentifier("link")), undefined, args);
324
+ return ts__default["default"].factory.createCallExpression(ts__default["default"].factory.createPropertyAccessExpression(ts__default["default"].factory.createIdentifier("c"), ts__default["default"].factory.createIdentifier("image")), undefined, args);
287
325
  }
288
326
  function toExpression(value) {
289
327
  if (typeof value === "string") {
290
328
  // TODO: Use configuration/heuristics to determine use of single quote or double quote
291
329
  return ts__default["default"].factory.createStringLiteral(value);
292
330
  } else if (typeof value === "number") {
331
+ // TODO: do we want to do something like this for very large numbers?
332
+ // if (value > Number.MAX_SAFE_INTEGER) {
333
+ // return ts.factory.createBigIntLiteral(`${value}n`);
334
+ // }
335
+ // if (value < Number.MIN_SAFE_INTEGER) {
336
+ // return ts.factory.createPrefixUnaryExpression(
337
+ // ts.SyntaxKind.MinusToken,
338
+ // ts.factory.createBigIntLiteral(`${value}n`),
339
+ // );
340
+ // }
341
+ if (value < 0) {
342
+ return ts__default["default"].factory.createPrefixUnaryExpression(ts__default["default"].SyntaxKind.MinusToken, ts__default["default"].factory.createNumericLiteral(Math.abs(value)));
343
+ }
293
344
  return ts__default["default"].factory.createNumericLiteral(value);
294
345
  } else if (typeof value === "boolean") {
295
346
  return value ? ts__default["default"].factory.createTrue() : ts__default["default"].factory.createFalse();
@@ -299,12 +350,10 @@ function toExpression(value) {
299
350
  return ts__default["default"].factory.createArrayLiteralExpression(value.map(toExpression));
300
351
  } else if (typeof value === "object") {
301
352
  if (isValFileValue(value)) {
302
- if (isValRichTextImageValue(value)) {
303
- return createValRichTextImage(value);
304
- }
305
353
  return createValFileReference(value);
306
- } else if (isValLinkValue(value)) {
307
- return createValLink(value);
354
+ }
355
+ if (isValImageValue(value)) {
356
+ return createValImageReference(value);
308
357
  }
309
358
  return ts__default["default"].factory.createObjectLiteralExpression(Object.entries(value).map(([key, value]) => createPropertyAssignment(key, value)));
310
359
  } else {
@@ -458,6 +507,25 @@ function replaceInNode(document, node, key, value) {
458
507
  ts__default["default"].factory.createObjectLiteralExpression([ts__default["default"].factory.createPropertyAssignment(key, metadataArgNode)]), key, value);
459
508
  }));
460
509
  }
510
+ } else if (isValImageMethodCall(node)) {
511
+ if (key === core.FILE_REF_PROP) {
512
+ if (typeof value !== "string") {
513
+ return fp.result.err(new patch.PatchError("Cannot replace c.image reference with non-string value"));
514
+ }
515
+ return fp.pipe(findValImageNodeArg(node), fp.result.map(refNode => replaceNodeValue(document, refNode, value)));
516
+ } else {
517
+ return fp.pipe(findValImageMetadataArg(node), fp.result.flatMap(metadataArgNode => {
518
+ if (!metadataArgNode) {
519
+ return fp.result.err(new patch.PatchError("Cannot replace in c.image metadata when it does not exist"));
520
+ }
521
+ if (key !== "metadata") {
522
+ return fp.result.err(new patch.PatchError(`Cannot replace c.image metadata key ${key} when it does not exist`));
523
+ }
524
+ return replaceInNode(document,
525
+ // TODO: creating a fake object here might not be right - seems to work though
526
+ ts__default["default"].factory.createObjectLiteralExpression([ts__default["default"].factory.createPropertyAssignment(key, metadataArgNode)]), key, value);
527
+ }));
528
+ }
461
529
  } else {
462
530
  return fp.result.err(shallowValidateExpression(node) ?? new patch.PatchError("Cannot replace in non-object/array"));
463
531
  }
@@ -479,6 +547,11 @@ function getFromNode(node, key) {
479
547
  return findValFileNodeArg(node);
480
548
  }
481
549
  return findValFileMetadataArg(node);
550
+ } else if (isValImageMethodCall(node)) {
551
+ if (key === core.FILE_REF_PROP) {
552
+ return findValImageNodeArg(node);
553
+ }
554
+ return findValImageMetadataArg(node);
482
555
  } else {
483
556
  return fp.result.err(shallowValidateExpression(node) ?? new patch.PatchError("Cannot access non-object/array"));
484
557
  }
@@ -522,6 +595,17 @@ function removeFromNode(document, node, key) {
522
595
  return removeFromNode(document, metadataArgNode, key);
523
596
  }));
524
597
  }
598
+ } else if (isValImageMethodCall(node)) {
599
+ if (key === core.FILE_REF_PROP) {
600
+ return fp.result.err(new patch.PatchError("Cannot remove a ref from c.file"));
601
+ } else {
602
+ return fp.pipe(findValImageMetadataArg(node), fp.result.flatMap(metadataArgNode => {
603
+ if (!metadataArgNode) {
604
+ return fp.result.err(new patch.PatchError("Cannot remove from c.image metadata when it does not exist"));
605
+ }
606
+ return removeFromNode(document, metadataArgNode, key);
607
+ }));
608
+ }
525
609
  } else {
526
610
  return fp.result.err(shallowValidateExpression(node) ?? new patch.PatchError("Cannot remove from non-object/array"));
527
611
  }
@@ -534,17 +618,14 @@ function isValFileValue(value) {
534
618
  // TODO: replace the below with this:
535
619
  // VAL_EXTENSION in value &&
536
620
  // value[VAL_EXTENSION] === "file" &&
537
- core.FILE_REF_PROP in value && typeof value[core.FILE_REF_PROP] === "string");
621
+ core.FILE_REF_PROP in value && typeof value[core.FILE_REF_PROP] === "string" && value[core.FILE_REF_SUBTYPE_TAG] !== "image");
538
622
  }
539
- function isValRichTextImageValue(value) {
623
+ function isValImageValue(value) {
540
624
  return !!(typeof value === "object" && value &&
541
625
  // TODO: replace the below with this:
542
626
  // VAL_EXTENSION in value &&
543
627
  // value[VAL_EXTENSION] === "file" &&
544
- core.FILE_REF_PROP in value && typeof value[core.FILE_REF_PROP] === "string" && typeof value[core.FILE_REF_SUBTYPE_TAG] === "string" && value[core.FILE_REF_SUBTYPE_TAG] === core.RT_IMAGE_TAG);
545
- }
546
- function isValLinkValue(value) {
547
- return !!(typeof value === "object" && value && core.VAL_EXTENSION in value && value[core.VAL_EXTENSION] === "link");
628
+ core.FILE_REF_PROP in value && typeof value[core.FILE_REF_PROP] === "string" && value[core.FILE_REF_SUBTYPE_TAG] === "image");
548
629
  }
549
630
  function addToNode(document, node, key, value) {
550
631
  if (ts__default["default"].isArrayLiteralExpression(node)) {
@@ -577,6 +658,23 @@ function addToNode(document, node, key, value) {
577
658
  return fp.result.ok([insertAt(document, node.arguments, node.arguments.length, toExpression(value))]);
578
659
  }));
579
660
  }
661
+ } else if (isValImageMethodCall(node)) {
662
+ if (key === core.FILE_REF_PROP) {
663
+ if (typeof value !== "string") {
664
+ return fp.result.err(new patch.PatchError(`Cannot add ${core.FILE_REF_PROP} key to c.image with non-string value`));
665
+ }
666
+ return fp.pipe(findValImageNodeArg(node), fp.result.map(arg => replaceNodeValue(document, arg, value)));
667
+ } else {
668
+ return fp.pipe(findValImageMetadataArg(node), fp.result.flatMap(metadataArgNode => {
669
+ if (metadataArgNode) {
670
+ return fp.result.err(new patch.PatchError("Cannot add metadata to c.image when it already exists"));
671
+ }
672
+ if (key !== "metadata") {
673
+ return fp.result.err(new patch.PatchError(`Cannot add ${key} key to c.image: only metadata is allowed`));
674
+ }
675
+ return fp.result.ok([insertAt(document, node.arguments, node.arguments.length, toExpression(value))]);
676
+ }));
677
+ }
580
678
  } else {
581
679
  return fp.result.err(shallowValidateExpression(node) ?? new patch.PatchError("Cannot add to non-object/array"));
582
680
  }
@@ -2846,7 +2944,7 @@ class FSOpsHost {
2846
2944
  // TODO: do we want async operations here?
2847
2945
  deleteDir(dir) {
2848
2946
  if (this.directoryExists(dir)) {
2849
- fs__default["default"].rmdirSync(dir, {
2947
+ fs__default["default"].rmSync(dir, {
2850
2948
  recursive: true
2851
2949
  });
2852
2950
  }
@@ -95,7 +95,7 @@ function validateObjectProperties(nodes) {
95
95
  * validating its children.
96
96
  */
97
97
  function shallowValidateExpression(value) {
98
- return ts__default["default"].isStringLiteralLike(value) || ts__default["default"].isNumericLiteral(value) || value.kind === ts__default["default"].SyntaxKind.TrueKeyword || value.kind === ts__default["default"].SyntaxKind.FalseKeyword || value.kind === ts__default["default"].SyntaxKind.NullKeyword || ts__default["default"].isArrayLiteralExpression(value) || ts__default["default"].isObjectLiteralExpression(value) || isValFileMethodCall(value) ? undefined : new ValSyntaxError("Expression must be a literal or call c.file", value);
98
+ return ts__default["default"].isStringLiteralLike(value) || ts__default["default"].isNumericLiteral(value) || value.kind === ts__default["default"].SyntaxKind.TrueKeyword || value.kind === ts__default["default"].SyntaxKind.FalseKeyword || value.kind === ts__default["default"].SyntaxKind.NullKeyword || ts__default["default"].isArrayLiteralExpression(value) || ts__default["default"].isObjectLiteralExpression(value) || isValFileMethodCall(value) || isValImageMethodCall(value) ? undefined : new ValSyntaxError("Expression must be a literal or call c.file", value);
99
99
  }
100
100
 
101
101
  /**
@@ -136,6 +136,23 @@ function evaluateExpression(value) {
136
136
  });
137
137
  }
138
138
  }));
139
+ } else if (isValImageMethodCall(value)) {
140
+ return fp.pipe(findValImageNodeArg(value), fp.result.flatMap(ref => {
141
+ if (value.arguments.length === 2) {
142
+ return fp.pipe(evaluateExpression(value.arguments[1]), fp.result.map(metadata => ({
143
+ [core.FILE_REF_PROP]: ref.text,
144
+ _type: "file",
145
+ [core.FILE_REF_SUBTYPE_TAG]: "image",
146
+ metadata
147
+ })));
148
+ } else {
149
+ return fp.result.ok({
150
+ [core.FILE_REF_PROP]: ref.text,
151
+ _type: "file",
152
+ [core.FILE_REF_SUBTYPE_TAG]: "image"
153
+ });
154
+ }
155
+ }));
139
156
  } else {
140
157
  return fp.result.err(new ValSyntaxError("Expression must be a literal or call c.file", value));
141
158
  }
@@ -154,6 +171,9 @@ function findObjectPropertyAssignment(value, key) {
154
171
  function isValFileMethodCall(node) {
155
172
  return ts__default["default"].isCallExpression(node) && ts__default["default"].isPropertyAccessExpression(node.expression) && ts__default["default"].isIdentifier(node.expression.expression) && node.expression.expression.text === "c" && node.expression.name.text === "file";
156
173
  }
174
+ function isValImageMethodCall(node) {
175
+ return ts__default["default"].isCallExpression(node) && ts__default["default"].isPropertyAccessExpression(node.expression) && ts__default["default"].isIdentifier(node.expression.expression) && node.expression.expression.text === "c" && node.expression.name.text === "image";
176
+ }
157
177
  function findValFileNodeArg(node) {
158
178
  if (node.arguments.length === 0) {
159
179
  return fp.result.err(new ValSyntaxError(`Invalid c.file() call: missing ref argument`, node));
@@ -165,6 +185,17 @@ function findValFileNodeArg(node) {
165
185
  const refNode = node.arguments[0];
166
186
  return fp.result.ok(refNode);
167
187
  }
188
+ function findValImageNodeArg(node) {
189
+ if (node.arguments.length === 0) {
190
+ return fp.result.err(new ValSyntaxError(`Invalid c.image() call: missing ref argument`, node));
191
+ } else if (node.arguments.length > 2) {
192
+ return fp.result.err(new ValSyntaxError(`Invalid c.image() call: too many arguments ${node.arguments.length}}`, node));
193
+ } else if (!ts__default["default"].isStringLiteral(node.arguments[0])) {
194
+ return fp.result.err(new ValSyntaxError(`Invalid c.image() call: ref must be a string literal`, node));
195
+ }
196
+ const refNode = node.arguments[0];
197
+ return fp.result.ok(refNode);
198
+ }
168
199
  function findValFileMetadataArg(node) {
169
200
  if (node.arguments.length === 0) {
170
201
  return fp.result.err(new ValSyntaxError(`Invalid c.file() call: missing ref argument`, node));
@@ -178,6 +209,19 @@ function findValFileMetadataArg(node) {
178
209
  }
179
210
  return fp.result.ok(undefined);
180
211
  }
212
+ function findValImageMetadataArg(node) {
213
+ if (node.arguments.length === 0) {
214
+ return fp.result.err(new ValSyntaxError(`Invalid c.image() call: missing ref argument`, node));
215
+ } else if (node.arguments.length > 2) {
216
+ return fp.result.err(new ValSyntaxError(`Invalid c.image() call: too many arguments ${node.arguments.length}}`, node));
217
+ } else if (node.arguments.length === 2) {
218
+ if (!ts__default["default"].isObjectLiteralExpression(node.arguments[1])) {
219
+ return fp.result.err(new ValSyntaxError(`Invalid c.image() call: metadata must be a object literal`, node));
220
+ }
221
+ return fp.result.ok(node.arguments[1]);
222
+ }
223
+ return fp.result.ok(undefined);
224
+ }
181
225
 
182
226
  /**
183
227
  * Given a list of expressions, validates that all the expressions are not
@@ -272,24 +316,31 @@ function createValFileReference(value) {
272
316
  }
273
317
  return ts__default["default"].factory.createCallExpression(ts__default["default"].factory.createPropertyAccessExpression(ts__default["default"].factory.createIdentifier("c"), ts__default["default"].factory.createIdentifier("file")), undefined, args);
274
318
  }
275
- function createValRichTextImage(value) {
319
+ function createValImageReference(value) {
276
320
  const args = [ts__default["default"].factory.createStringLiteral(value[core.FILE_REF_PROP])];
277
321
  if (value.metadata) {
278
322
  args.push(toExpression(value.metadata));
279
323
  }
280
- return ts__default["default"].factory.createCallExpression(ts__default["default"].factory.createPropertyAccessExpression(ts__default["default"].factory.createPropertyAccessExpression(ts__default["default"].factory.createIdentifier("c"), "rt"), ts__default["default"].factory.createIdentifier("image")), undefined, args);
281
- }
282
- function createValLink(value) {
283
- const args = [ts__default["default"].factory.createStringLiteral(value.children[0]), toExpression({
284
- href: value.href
285
- })];
286
- return ts__default["default"].factory.createCallExpression(ts__default["default"].factory.createPropertyAccessExpression(ts__default["default"].factory.createPropertyAccessExpression(ts__default["default"].factory.createIdentifier("c"), "rt"), ts__default["default"].factory.createIdentifier("link")), undefined, args);
324
+ return ts__default["default"].factory.createCallExpression(ts__default["default"].factory.createPropertyAccessExpression(ts__default["default"].factory.createIdentifier("c"), ts__default["default"].factory.createIdentifier("image")), undefined, args);
287
325
  }
288
326
  function toExpression(value) {
289
327
  if (typeof value === "string") {
290
328
  // TODO: Use configuration/heuristics to determine use of single quote or double quote
291
329
  return ts__default["default"].factory.createStringLiteral(value);
292
330
  } else if (typeof value === "number") {
331
+ // TODO: do we want to do something like this for very large numbers?
332
+ // if (value > Number.MAX_SAFE_INTEGER) {
333
+ // return ts.factory.createBigIntLiteral(`${value}n`);
334
+ // }
335
+ // if (value < Number.MIN_SAFE_INTEGER) {
336
+ // return ts.factory.createPrefixUnaryExpression(
337
+ // ts.SyntaxKind.MinusToken,
338
+ // ts.factory.createBigIntLiteral(`${value}n`),
339
+ // );
340
+ // }
341
+ if (value < 0) {
342
+ return ts__default["default"].factory.createPrefixUnaryExpression(ts__default["default"].SyntaxKind.MinusToken, ts__default["default"].factory.createNumericLiteral(Math.abs(value)));
343
+ }
293
344
  return ts__default["default"].factory.createNumericLiteral(value);
294
345
  } else if (typeof value === "boolean") {
295
346
  return value ? ts__default["default"].factory.createTrue() : ts__default["default"].factory.createFalse();
@@ -299,12 +350,10 @@ function toExpression(value) {
299
350
  return ts__default["default"].factory.createArrayLiteralExpression(value.map(toExpression));
300
351
  } else if (typeof value === "object") {
301
352
  if (isValFileValue(value)) {
302
- if (isValRichTextImageValue(value)) {
303
- return createValRichTextImage(value);
304
- }
305
353
  return createValFileReference(value);
306
- } else if (isValLinkValue(value)) {
307
- return createValLink(value);
354
+ }
355
+ if (isValImageValue(value)) {
356
+ return createValImageReference(value);
308
357
  }
309
358
  return ts__default["default"].factory.createObjectLiteralExpression(Object.entries(value).map(([key, value]) => createPropertyAssignment(key, value)));
310
359
  } else {
@@ -458,6 +507,25 @@ function replaceInNode(document, node, key, value) {
458
507
  ts__default["default"].factory.createObjectLiteralExpression([ts__default["default"].factory.createPropertyAssignment(key, metadataArgNode)]), key, value);
459
508
  }));
460
509
  }
510
+ } else if (isValImageMethodCall(node)) {
511
+ if (key === core.FILE_REF_PROP) {
512
+ if (typeof value !== "string") {
513
+ return fp.result.err(new patch.PatchError("Cannot replace c.image reference with non-string value"));
514
+ }
515
+ return fp.pipe(findValImageNodeArg(node), fp.result.map(refNode => replaceNodeValue(document, refNode, value)));
516
+ } else {
517
+ return fp.pipe(findValImageMetadataArg(node), fp.result.flatMap(metadataArgNode => {
518
+ if (!metadataArgNode) {
519
+ return fp.result.err(new patch.PatchError("Cannot replace in c.image metadata when it does not exist"));
520
+ }
521
+ if (key !== "metadata") {
522
+ return fp.result.err(new patch.PatchError(`Cannot replace c.image metadata key ${key} when it does not exist`));
523
+ }
524
+ return replaceInNode(document,
525
+ // TODO: creating a fake object here might not be right - seems to work though
526
+ ts__default["default"].factory.createObjectLiteralExpression([ts__default["default"].factory.createPropertyAssignment(key, metadataArgNode)]), key, value);
527
+ }));
528
+ }
461
529
  } else {
462
530
  return fp.result.err(shallowValidateExpression(node) ?? new patch.PatchError("Cannot replace in non-object/array"));
463
531
  }
@@ -479,6 +547,11 @@ function getFromNode(node, key) {
479
547
  return findValFileNodeArg(node);
480
548
  }
481
549
  return findValFileMetadataArg(node);
550
+ } else if (isValImageMethodCall(node)) {
551
+ if (key === core.FILE_REF_PROP) {
552
+ return findValImageNodeArg(node);
553
+ }
554
+ return findValImageMetadataArg(node);
482
555
  } else {
483
556
  return fp.result.err(shallowValidateExpression(node) ?? new patch.PatchError("Cannot access non-object/array"));
484
557
  }
@@ -522,6 +595,17 @@ function removeFromNode(document, node, key) {
522
595
  return removeFromNode(document, metadataArgNode, key);
523
596
  }));
524
597
  }
598
+ } else if (isValImageMethodCall(node)) {
599
+ if (key === core.FILE_REF_PROP) {
600
+ return fp.result.err(new patch.PatchError("Cannot remove a ref from c.file"));
601
+ } else {
602
+ return fp.pipe(findValImageMetadataArg(node), fp.result.flatMap(metadataArgNode => {
603
+ if (!metadataArgNode) {
604
+ return fp.result.err(new patch.PatchError("Cannot remove from c.image metadata when it does not exist"));
605
+ }
606
+ return removeFromNode(document, metadataArgNode, key);
607
+ }));
608
+ }
525
609
  } else {
526
610
  return fp.result.err(shallowValidateExpression(node) ?? new patch.PatchError("Cannot remove from non-object/array"));
527
611
  }
@@ -534,17 +618,14 @@ function isValFileValue(value) {
534
618
  // TODO: replace the below with this:
535
619
  // VAL_EXTENSION in value &&
536
620
  // value[VAL_EXTENSION] === "file" &&
537
- core.FILE_REF_PROP in value && typeof value[core.FILE_REF_PROP] === "string");
621
+ core.FILE_REF_PROP in value && typeof value[core.FILE_REF_PROP] === "string" && value[core.FILE_REF_SUBTYPE_TAG] !== "image");
538
622
  }
539
- function isValRichTextImageValue(value) {
623
+ function isValImageValue(value) {
540
624
  return !!(typeof value === "object" && value &&
541
625
  // TODO: replace the below with this:
542
626
  // VAL_EXTENSION in value &&
543
627
  // value[VAL_EXTENSION] === "file" &&
544
- core.FILE_REF_PROP in value && typeof value[core.FILE_REF_PROP] === "string" && typeof value[core.FILE_REF_SUBTYPE_TAG] === "string" && value[core.FILE_REF_SUBTYPE_TAG] === core.RT_IMAGE_TAG);
545
- }
546
- function isValLinkValue(value) {
547
- return !!(typeof value === "object" && value && core.VAL_EXTENSION in value && value[core.VAL_EXTENSION] === "link");
628
+ core.FILE_REF_PROP in value && typeof value[core.FILE_REF_PROP] === "string" && value[core.FILE_REF_SUBTYPE_TAG] === "image");
548
629
  }
549
630
  function addToNode(document, node, key, value) {
550
631
  if (ts__default["default"].isArrayLiteralExpression(node)) {
@@ -577,6 +658,23 @@ function addToNode(document, node, key, value) {
577
658
  return fp.result.ok([insertAt(document, node.arguments, node.arguments.length, toExpression(value))]);
578
659
  }));
579
660
  }
661
+ } else if (isValImageMethodCall(node)) {
662
+ if (key === core.FILE_REF_PROP) {
663
+ if (typeof value !== "string") {
664
+ return fp.result.err(new patch.PatchError(`Cannot add ${core.FILE_REF_PROP} key to c.image with non-string value`));
665
+ }
666
+ return fp.pipe(findValImageNodeArg(node), fp.result.map(arg => replaceNodeValue(document, arg, value)));
667
+ } else {
668
+ return fp.pipe(findValImageMetadataArg(node), fp.result.flatMap(metadataArgNode => {
669
+ if (metadataArgNode) {
670
+ return fp.result.err(new patch.PatchError("Cannot add metadata to c.image when it already exists"));
671
+ }
672
+ if (key !== "metadata") {
673
+ return fp.result.err(new patch.PatchError(`Cannot add ${key} key to c.image: only metadata is allowed`));
674
+ }
675
+ return fp.result.ok([insertAt(document, node.arguments, node.arguments.length, toExpression(value))]);
676
+ }));
677
+ }
580
678
  } else {
581
679
  return fp.result.err(shallowValidateExpression(node) ?? new patch.PatchError("Cannot add to non-object/array"));
582
680
  }
@@ -2846,7 +2944,7 @@ class FSOpsHost {
2846
2944
  // TODO: do we want async operations here?
2847
2945
  deleteDir(dir) {
2848
2946
  if (this.directoryExists(dir)) {
2849
- fs__default["default"].rmdirSync(dir, {
2947
+ fs__default["default"].rmSync(dir, {
2850
2948
  recursive: true
2851
2949
  });
2852
2950
  }
@@ -1,7 +1,7 @@
1
1
  import { newQuickJSWASMModule } from 'quickjs-emscripten';
2
2
  import ts from 'typescript';
3
3
  import { result, pipe } from '@valbuild/core/fp';
4
- import { FILE_REF_PROP, FILE_REF_SUBTYPE_TAG, RT_IMAGE_TAG, VAL_EXTENSION, derefPatch, Internal, Schema, ImageSchema, RichTextSchema, FileSchema } from '@valbuild/core';
4
+ import { FILE_REF_PROP, FILE_REF_SUBTYPE_TAG, derefPatch, Internal, Schema, ImageSchema, RichTextSchema, FileSchema, VAL_EXTENSION } from '@valbuild/core';
5
5
  import { deepEqual, isNotRoot, PatchError, parseAndValidateArrayIndex, applyPatch, JSONOps, deepClone, sourceToPatchPath } from '@valbuild/core/patch';
6
6
  import * as fsPath from 'path';
7
7
  import fsPath__default from 'path';
@@ -65,7 +65,7 @@ function validateObjectProperties(nodes) {
65
65
  * validating its children.
66
66
  */
67
67
  function shallowValidateExpression(value) {
68
- return ts.isStringLiteralLike(value) || ts.isNumericLiteral(value) || value.kind === ts.SyntaxKind.TrueKeyword || value.kind === ts.SyntaxKind.FalseKeyword || value.kind === ts.SyntaxKind.NullKeyword || ts.isArrayLiteralExpression(value) || ts.isObjectLiteralExpression(value) || isValFileMethodCall(value) ? undefined : new ValSyntaxError("Expression must be a literal or call c.file", value);
68
+ return ts.isStringLiteralLike(value) || ts.isNumericLiteral(value) || value.kind === ts.SyntaxKind.TrueKeyword || value.kind === ts.SyntaxKind.FalseKeyword || value.kind === ts.SyntaxKind.NullKeyword || ts.isArrayLiteralExpression(value) || ts.isObjectLiteralExpression(value) || isValFileMethodCall(value) || isValImageMethodCall(value) ? undefined : new ValSyntaxError("Expression must be a literal or call c.file", value);
69
69
  }
70
70
 
71
71
  /**
@@ -106,6 +106,23 @@ function evaluateExpression(value) {
106
106
  });
107
107
  }
108
108
  }));
109
+ } else if (isValImageMethodCall(value)) {
110
+ return pipe(findValImageNodeArg(value), result.flatMap(ref => {
111
+ if (value.arguments.length === 2) {
112
+ return pipe(evaluateExpression(value.arguments[1]), result.map(metadata => ({
113
+ [FILE_REF_PROP]: ref.text,
114
+ _type: "file",
115
+ [FILE_REF_SUBTYPE_TAG]: "image",
116
+ metadata
117
+ })));
118
+ } else {
119
+ return result.ok({
120
+ [FILE_REF_PROP]: ref.text,
121
+ _type: "file",
122
+ [FILE_REF_SUBTYPE_TAG]: "image"
123
+ });
124
+ }
125
+ }));
109
126
  } else {
110
127
  return result.err(new ValSyntaxError("Expression must be a literal or call c.file", value));
111
128
  }
@@ -124,6 +141,9 @@ function findObjectPropertyAssignment(value, key) {
124
141
  function isValFileMethodCall(node) {
125
142
  return ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.expression) && node.expression.expression.text === "c" && node.expression.name.text === "file";
126
143
  }
144
+ function isValImageMethodCall(node) {
145
+ return ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.expression) && node.expression.expression.text === "c" && node.expression.name.text === "image";
146
+ }
127
147
  function findValFileNodeArg(node) {
128
148
  if (node.arguments.length === 0) {
129
149
  return result.err(new ValSyntaxError(`Invalid c.file() call: missing ref argument`, node));
@@ -135,6 +155,17 @@ function findValFileNodeArg(node) {
135
155
  const refNode = node.arguments[0];
136
156
  return result.ok(refNode);
137
157
  }
158
+ function findValImageNodeArg(node) {
159
+ if (node.arguments.length === 0) {
160
+ return result.err(new ValSyntaxError(`Invalid c.image() call: missing ref argument`, node));
161
+ } else if (node.arguments.length > 2) {
162
+ return result.err(new ValSyntaxError(`Invalid c.image() call: too many arguments ${node.arguments.length}}`, node));
163
+ } else if (!ts.isStringLiteral(node.arguments[0])) {
164
+ return result.err(new ValSyntaxError(`Invalid c.image() call: ref must be a string literal`, node));
165
+ }
166
+ const refNode = node.arguments[0];
167
+ return result.ok(refNode);
168
+ }
138
169
  function findValFileMetadataArg(node) {
139
170
  if (node.arguments.length === 0) {
140
171
  return result.err(new ValSyntaxError(`Invalid c.file() call: missing ref argument`, node));
@@ -148,6 +179,19 @@ function findValFileMetadataArg(node) {
148
179
  }
149
180
  return result.ok(undefined);
150
181
  }
182
+ function findValImageMetadataArg(node) {
183
+ if (node.arguments.length === 0) {
184
+ return result.err(new ValSyntaxError(`Invalid c.image() call: missing ref argument`, node));
185
+ } else if (node.arguments.length > 2) {
186
+ return result.err(new ValSyntaxError(`Invalid c.image() call: too many arguments ${node.arguments.length}}`, node));
187
+ } else if (node.arguments.length === 2) {
188
+ if (!ts.isObjectLiteralExpression(node.arguments[1])) {
189
+ return result.err(new ValSyntaxError(`Invalid c.image() call: metadata must be a object literal`, node));
190
+ }
191
+ return result.ok(node.arguments[1]);
192
+ }
193
+ return result.ok(undefined);
194
+ }
151
195
 
152
196
  /**
153
197
  * Given a list of expressions, validates that all the expressions are not
@@ -242,24 +286,31 @@ function createValFileReference(value) {
242
286
  }
243
287
  return ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("c"), ts.factory.createIdentifier("file")), undefined, args);
244
288
  }
245
- function createValRichTextImage(value) {
289
+ function createValImageReference(value) {
246
290
  const args = [ts.factory.createStringLiteral(value[FILE_REF_PROP])];
247
291
  if (value.metadata) {
248
292
  args.push(toExpression(value.metadata));
249
293
  }
250
- return ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("c"), "rt"), ts.factory.createIdentifier("image")), undefined, args);
251
- }
252
- function createValLink(value) {
253
- const args = [ts.factory.createStringLiteral(value.children[0]), toExpression({
254
- href: value.href
255
- })];
256
- return ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("c"), "rt"), ts.factory.createIdentifier("link")), undefined, args);
294
+ return ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("c"), ts.factory.createIdentifier("image")), undefined, args);
257
295
  }
258
296
  function toExpression(value) {
259
297
  if (typeof value === "string") {
260
298
  // TODO: Use configuration/heuristics to determine use of single quote or double quote
261
299
  return ts.factory.createStringLiteral(value);
262
300
  } else if (typeof value === "number") {
301
+ // TODO: do we want to do something like this for very large numbers?
302
+ // if (value > Number.MAX_SAFE_INTEGER) {
303
+ // return ts.factory.createBigIntLiteral(`${value}n`);
304
+ // }
305
+ // if (value < Number.MIN_SAFE_INTEGER) {
306
+ // return ts.factory.createPrefixUnaryExpression(
307
+ // ts.SyntaxKind.MinusToken,
308
+ // ts.factory.createBigIntLiteral(`${value}n`),
309
+ // );
310
+ // }
311
+ if (value < 0) {
312
+ return ts.factory.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, ts.factory.createNumericLiteral(Math.abs(value)));
313
+ }
263
314
  return ts.factory.createNumericLiteral(value);
264
315
  } else if (typeof value === "boolean") {
265
316
  return value ? ts.factory.createTrue() : ts.factory.createFalse();
@@ -269,12 +320,10 @@ function toExpression(value) {
269
320
  return ts.factory.createArrayLiteralExpression(value.map(toExpression));
270
321
  } else if (typeof value === "object") {
271
322
  if (isValFileValue(value)) {
272
- if (isValRichTextImageValue(value)) {
273
- return createValRichTextImage(value);
274
- }
275
323
  return createValFileReference(value);
276
- } else if (isValLinkValue(value)) {
277
- return createValLink(value);
324
+ }
325
+ if (isValImageValue(value)) {
326
+ return createValImageReference(value);
278
327
  }
279
328
  return ts.factory.createObjectLiteralExpression(Object.entries(value).map(([key, value]) => createPropertyAssignment(key, value)));
280
329
  } else {
@@ -428,6 +477,25 @@ function replaceInNode(document, node, key, value) {
428
477
  ts.factory.createObjectLiteralExpression([ts.factory.createPropertyAssignment(key, metadataArgNode)]), key, value);
429
478
  }));
430
479
  }
480
+ } else if (isValImageMethodCall(node)) {
481
+ if (key === FILE_REF_PROP) {
482
+ if (typeof value !== "string") {
483
+ return result.err(new PatchError("Cannot replace c.image reference with non-string value"));
484
+ }
485
+ return pipe(findValImageNodeArg(node), result.map(refNode => replaceNodeValue(document, refNode, value)));
486
+ } else {
487
+ return pipe(findValImageMetadataArg(node), result.flatMap(metadataArgNode => {
488
+ if (!metadataArgNode) {
489
+ return result.err(new PatchError("Cannot replace in c.image metadata when it does not exist"));
490
+ }
491
+ if (key !== "metadata") {
492
+ return result.err(new PatchError(`Cannot replace c.image metadata key ${key} when it does not exist`));
493
+ }
494
+ return replaceInNode(document,
495
+ // TODO: creating a fake object here might not be right - seems to work though
496
+ ts.factory.createObjectLiteralExpression([ts.factory.createPropertyAssignment(key, metadataArgNode)]), key, value);
497
+ }));
498
+ }
431
499
  } else {
432
500
  return result.err(shallowValidateExpression(node) ?? new PatchError("Cannot replace in non-object/array"));
433
501
  }
@@ -449,6 +517,11 @@ function getFromNode(node, key) {
449
517
  return findValFileNodeArg(node);
450
518
  }
451
519
  return findValFileMetadataArg(node);
520
+ } else if (isValImageMethodCall(node)) {
521
+ if (key === FILE_REF_PROP) {
522
+ return findValImageNodeArg(node);
523
+ }
524
+ return findValImageMetadataArg(node);
452
525
  } else {
453
526
  return result.err(shallowValidateExpression(node) ?? new PatchError("Cannot access non-object/array"));
454
527
  }
@@ -492,6 +565,17 @@ function removeFromNode(document, node, key) {
492
565
  return removeFromNode(document, metadataArgNode, key);
493
566
  }));
494
567
  }
568
+ } else if (isValImageMethodCall(node)) {
569
+ if (key === FILE_REF_PROP) {
570
+ return result.err(new PatchError("Cannot remove a ref from c.file"));
571
+ } else {
572
+ return pipe(findValImageMetadataArg(node), result.flatMap(metadataArgNode => {
573
+ if (!metadataArgNode) {
574
+ return result.err(new PatchError("Cannot remove from c.image metadata when it does not exist"));
575
+ }
576
+ return removeFromNode(document, metadataArgNode, key);
577
+ }));
578
+ }
495
579
  } else {
496
580
  return result.err(shallowValidateExpression(node) ?? new PatchError("Cannot remove from non-object/array"));
497
581
  }
@@ -504,17 +588,14 @@ function isValFileValue(value) {
504
588
  // TODO: replace the below with this:
505
589
  // VAL_EXTENSION in value &&
506
590
  // value[VAL_EXTENSION] === "file" &&
507
- FILE_REF_PROP in value && typeof value[FILE_REF_PROP] === "string");
591
+ FILE_REF_PROP in value && typeof value[FILE_REF_PROP] === "string" && value[FILE_REF_SUBTYPE_TAG] !== "image");
508
592
  }
509
- function isValRichTextImageValue(value) {
593
+ function isValImageValue(value) {
510
594
  return !!(typeof value === "object" && value &&
511
595
  // TODO: replace the below with this:
512
596
  // VAL_EXTENSION in value &&
513
597
  // value[VAL_EXTENSION] === "file" &&
514
- FILE_REF_PROP in value && typeof value[FILE_REF_PROP] === "string" && typeof value[FILE_REF_SUBTYPE_TAG] === "string" && value[FILE_REF_SUBTYPE_TAG] === RT_IMAGE_TAG);
515
- }
516
- function isValLinkValue(value) {
517
- return !!(typeof value === "object" && value && VAL_EXTENSION in value && value[VAL_EXTENSION] === "link");
598
+ FILE_REF_PROP in value && typeof value[FILE_REF_PROP] === "string" && value[FILE_REF_SUBTYPE_TAG] === "image");
518
599
  }
519
600
  function addToNode(document, node, key, value) {
520
601
  if (ts.isArrayLiteralExpression(node)) {
@@ -547,6 +628,23 @@ function addToNode(document, node, key, value) {
547
628
  return result.ok([insertAt(document, node.arguments, node.arguments.length, toExpression(value))]);
548
629
  }));
549
630
  }
631
+ } else if (isValImageMethodCall(node)) {
632
+ if (key === FILE_REF_PROP) {
633
+ if (typeof value !== "string") {
634
+ return result.err(new PatchError(`Cannot add ${FILE_REF_PROP} key to c.image with non-string value`));
635
+ }
636
+ return pipe(findValImageNodeArg(node), result.map(arg => replaceNodeValue(document, arg, value)));
637
+ } else {
638
+ return pipe(findValImageMetadataArg(node), result.flatMap(metadataArgNode => {
639
+ if (metadataArgNode) {
640
+ return result.err(new PatchError("Cannot add metadata to c.image when it already exists"));
641
+ }
642
+ if (key !== "metadata") {
643
+ return result.err(new PatchError(`Cannot add ${key} key to c.image: only metadata is allowed`));
644
+ }
645
+ return result.ok([insertAt(document, node.arguments, node.arguments.length, toExpression(value))]);
646
+ }));
647
+ }
550
648
  } else {
551
649
  return result.err(shallowValidateExpression(node) ?? new PatchError("Cannot add to non-object/array"));
552
650
  }
@@ -2816,7 +2914,7 @@ class FSOpsHost {
2816
2914
  // TODO: do we want async operations here?
2817
2915
  deleteDir(dir) {
2818
2916
  if (this.directoryExists(dir)) {
2819
- fs.rmdirSync(dir, {
2917
+ fs.rmSync(dir, {
2820
2918
  recursive: true
2821
2919
  });
2822
2920
  }
package/package.json CHANGED
@@ -12,7 +12,7 @@
12
12
  "./package.json": "./package.json"
13
13
  },
14
14
  "types": "dist/valbuild-server.cjs.d.ts",
15
- "version": "0.65.2",
15
+ "version": "0.67.0",
16
16
  "scripts": {
17
17
  "typecheck": "tsc --noEmit",
18
18
  "test": "jest",
@@ -23,9 +23,9 @@
23
23
  "@types/jest": "^29.2.5"
24
24
  },
25
25
  "dependencies": {
26
- "@valbuild/core": "~0.65.2",
27
- "@valbuild/shared": "~0.65.2",
28
- "@valbuild/ui": "~0.65.2",
26
+ "@valbuild/core": "~0.67.0",
27
+ "@valbuild/shared": "~0.67.0",
28
+ "@valbuild/ui": "~0.67.0",
29
29
  "chokidar": "^4.0.1",
30
30
  "image-size": "^1.0.2",
31
31
  "minimatch": "^3.0.4",