@valbuild/server 0.66.0 → 0.67.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.
@@ -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
  }
@@ -1738,7 +1836,7 @@ class ValOps {
1738
1836
  actual: currentValueMetadata[field],
1739
1837
  expected: fieldMetadata
1740
1838
  },
1741
- fixes: ["image:replace-metadata"]
1839
+ fixes: ["image:check-metadata"]
1742
1840
  }];
1743
1841
  }
1744
1842
  }
@@ -2082,7 +2180,7 @@ class ValOps {
2082
2180
  }
2083
2181
  function isOnlyFileCheckValidationError(validationError) {
2084
2182
  var _validationError$fixe;
2085
- if ((_validationError$fixe = validationError.fixes) !== null && _validationError$fixe !== void 0 && _validationError$fixe.every(f => f === "file:check-metadata" || f === "image:replace-metadata")) {
2183
+ if ((_validationError$fixe = validationError.fixes) !== null && _validationError$fixe !== void 0 && _validationError$fixe.every(f => f === "file:check-metadata" || f === "image:check-metadata")) {
2086
2184
  return true;
2087
2185
  }
2088
2186
  return false;
@@ -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
  }
@@ -5354,7 +5452,7 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
5354
5452
  const remainingErrors = [];
5355
5453
  const patch$1 = [];
5356
5454
  for (const fix of validationError.fixes || []) {
5357
- if (fix === "image:replace-metadata" || fix === "image:add-metadata") {
5455
+ if (fix === "image:check-metadata" || fix === "image:add-metadata") {
5358
5456
  const imageMetadata = await getImageMetadata();
5359
5457
  if (imageMetadata.width === undefined || imageMetadata.height === undefined) {
5360
5458
  remainingErrors.push({
@@ -5362,7 +5460,7 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
5362
5460
  message: "Failed to get image metadata",
5363
5461
  fixes: undefined
5364
5462
  });
5365
- } else if (fix === "image:replace-metadata") {
5463
+ } else if (fix === "image:check-metadata") {
5366
5464
  const currentValue = validationError.value;
5367
5465
  const metadataIsCorrect =
5368
5466
  // metadata is a prop that is an object
@@ -5373,7 +5471,6 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
5373
5471
  "height" in currentValue.metadata && currentValue.metadata.height === imageMetadata.height &&
5374
5472
  // mimeType is correct
5375
5473
  "mimeType" in currentValue.metadata && currentValue.metadata.mimeType === imageMetadata.mimeType;
5376
-
5377
5474
  // skips if the metadata is already correct
5378
5475
  if (!metadataIsCorrect) {
5379
5476
  if (apply) {
@@ -5381,6 +5478,8 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
5381
5478
  op: "replace",
5382
5479
  path: patch.sourceToPatchPath(sourcePath).concat("metadata"),
5383
5480
  value: {
5481
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5482
+ ...currentValue.metadata,
5384
5483
  width: imageMetadata.width,
5385
5484
  height: imageMetadata.height,
5386
5485
  mimeType: imageMetadata.mimeType
@@ -5449,6 +5548,8 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
5449
5548
  op: "replace",
5450
5549
  path: patch.sourceToPatchPath(sourcePath).concat("metadata"),
5451
5550
  value: {
5551
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5552
+ ...currentValue.metadata,
5452
5553
  ...(fileMetadata.mimeType ? {
5453
5554
  mimeType: fileMetadata.mimeType
5454
5555
  } : {})
@@ -5482,21 +5583,6 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
5482
5583
  }
5483
5584
  });
5484
5585
  }
5485
- } else if (fix === "fix:deprecated-richtext") {
5486
- if (!validationError.value) {
5487
- throw Error("Cannot fix richtext without a value");
5488
- }
5489
- patch$1.push({
5490
- op: "replace",
5491
- path: patch.sourceToPatchPath(sourcePath),
5492
- value: validationError.value
5493
- });
5494
- } else {
5495
- remainingErrors.push({
5496
- ...validationError,
5497
- message: `Unknown fix: ${fix}`,
5498
- fixes: undefined
5499
- });
5500
5586
  }
5501
5587
  }
5502
5588
  if (!validationError.fixes || validationError.fixes.length === 0) {
@@ -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
  }
@@ -1738,7 +1836,7 @@ class ValOps {
1738
1836
  actual: currentValueMetadata[field],
1739
1837
  expected: fieldMetadata
1740
1838
  },
1741
- fixes: ["image:replace-metadata"]
1839
+ fixes: ["image:check-metadata"]
1742
1840
  }];
1743
1841
  }
1744
1842
  }
@@ -2082,7 +2180,7 @@ class ValOps {
2082
2180
  }
2083
2181
  function isOnlyFileCheckValidationError(validationError) {
2084
2182
  var _validationError$fixe;
2085
- if ((_validationError$fixe = validationError.fixes) !== null && _validationError$fixe !== void 0 && _validationError$fixe.every(f => f === "file:check-metadata" || f === "image:replace-metadata")) {
2183
+ if ((_validationError$fixe = validationError.fixes) !== null && _validationError$fixe !== void 0 && _validationError$fixe.every(f => f === "file:check-metadata" || f === "image:check-metadata")) {
2086
2184
  return true;
2087
2185
  }
2088
2186
  return false;
@@ -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
  }
@@ -5354,7 +5452,7 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
5354
5452
  const remainingErrors = [];
5355
5453
  const patch$1 = [];
5356
5454
  for (const fix of validationError.fixes || []) {
5357
- if (fix === "image:replace-metadata" || fix === "image:add-metadata") {
5455
+ if (fix === "image:check-metadata" || fix === "image:add-metadata") {
5358
5456
  const imageMetadata = await getImageMetadata();
5359
5457
  if (imageMetadata.width === undefined || imageMetadata.height === undefined) {
5360
5458
  remainingErrors.push({
@@ -5362,7 +5460,7 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
5362
5460
  message: "Failed to get image metadata",
5363
5461
  fixes: undefined
5364
5462
  });
5365
- } else if (fix === "image:replace-metadata") {
5463
+ } else if (fix === "image:check-metadata") {
5366
5464
  const currentValue = validationError.value;
5367
5465
  const metadataIsCorrect =
5368
5466
  // metadata is a prop that is an object
@@ -5373,7 +5471,6 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
5373
5471
  "height" in currentValue.metadata && currentValue.metadata.height === imageMetadata.height &&
5374
5472
  // mimeType is correct
5375
5473
  "mimeType" in currentValue.metadata && currentValue.metadata.mimeType === imageMetadata.mimeType;
5376
-
5377
5474
  // skips if the metadata is already correct
5378
5475
  if (!metadataIsCorrect) {
5379
5476
  if (apply) {
@@ -5381,6 +5478,8 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
5381
5478
  op: "replace",
5382
5479
  path: patch.sourceToPatchPath(sourcePath).concat("metadata"),
5383
5480
  value: {
5481
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5482
+ ...currentValue.metadata,
5384
5483
  width: imageMetadata.width,
5385
5484
  height: imageMetadata.height,
5386
5485
  mimeType: imageMetadata.mimeType
@@ -5449,6 +5548,8 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
5449
5548
  op: "replace",
5450
5549
  path: patch.sourceToPatchPath(sourcePath).concat("metadata"),
5451
5550
  value: {
5551
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5552
+ ...currentValue.metadata,
5452
5553
  ...(fileMetadata.mimeType ? {
5453
5554
  mimeType: fileMetadata.mimeType
5454
5555
  } : {})
@@ -5482,21 +5583,6 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
5482
5583
  }
5483
5584
  });
5484
5585
  }
5485
- } else if (fix === "fix:deprecated-richtext") {
5486
- if (!validationError.value) {
5487
- throw Error("Cannot fix richtext without a value");
5488
- }
5489
- patch$1.push({
5490
- op: "replace",
5491
- path: patch.sourceToPatchPath(sourcePath),
5492
- value: validationError.value
5493
- });
5494
- } else {
5495
- remainingErrors.push({
5496
- ...validationError,
5497
- message: `Unknown fix: ${fix}`,
5498
- fixes: undefined
5499
- });
5500
5586
  }
5501
5587
  }
5502
5588
  if (!validationError.fixes || validationError.fixes.length === 0) {
@@ -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
  }
@@ -1708,7 +1806,7 @@ class ValOps {
1708
1806
  actual: currentValueMetadata[field],
1709
1807
  expected: fieldMetadata
1710
1808
  },
1711
- fixes: ["image:replace-metadata"]
1809
+ fixes: ["image:check-metadata"]
1712
1810
  }];
1713
1811
  }
1714
1812
  }
@@ -2052,7 +2150,7 @@ class ValOps {
2052
2150
  }
2053
2151
  function isOnlyFileCheckValidationError(validationError) {
2054
2152
  var _validationError$fixe;
2055
- if ((_validationError$fixe = validationError.fixes) !== null && _validationError$fixe !== void 0 && _validationError$fixe.every(f => f === "file:check-metadata" || f === "image:replace-metadata")) {
2153
+ if ((_validationError$fixe = validationError.fixes) !== null && _validationError$fixe !== void 0 && _validationError$fixe.every(f => f === "file:check-metadata" || f === "image:check-metadata")) {
2056
2154
  return true;
2057
2155
  }
2058
2156
  return false;
@@ -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
  }
@@ -5324,7 +5422,7 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
5324
5422
  const remainingErrors = [];
5325
5423
  const patch = [];
5326
5424
  for (const fix of validationError.fixes || []) {
5327
- if (fix === "image:replace-metadata" || fix === "image:add-metadata") {
5425
+ if (fix === "image:check-metadata" || fix === "image:add-metadata") {
5328
5426
  const imageMetadata = await getImageMetadata();
5329
5427
  if (imageMetadata.width === undefined || imageMetadata.height === undefined) {
5330
5428
  remainingErrors.push({
@@ -5332,7 +5430,7 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
5332
5430
  message: "Failed to get image metadata",
5333
5431
  fixes: undefined
5334
5432
  });
5335
- } else if (fix === "image:replace-metadata") {
5433
+ } else if (fix === "image:check-metadata") {
5336
5434
  const currentValue = validationError.value;
5337
5435
  const metadataIsCorrect =
5338
5436
  // metadata is a prop that is an object
@@ -5343,7 +5441,6 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
5343
5441
  "height" in currentValue.metadata && currentValue.metadata.height === imageMetadata.height &&
5344
5442
  // mimeType is correct
5345
5443
  "mimeType" in currentValue.metadata && currentValue.metadata.mimeType === imageMetadata.mimeType;
5346
-
5347
5444
  // skips if the metadata is already correct
5348
5445
  if (!metadataIsCorrect) {
5349
5446
  if (apply) {
@@ -5351,6 +5448,8 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
5351
5448
  op: "replace",
5352
5449
  path: sourceToPatchPath(sourcePath).concat("metadata"),
5353
5450
  value: {
5451
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5452
+ ...currentValue.metadata,
5354
5453
  width: imageMetadata.width,
5355
5454
  height: imageMetadata.height,
5356
5455
  mimeType: imageMetadata.mimeType
@@ -5419,6 +5518,8 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
5419
5518
  op: "replace",
5420
5519
  path: sourceToPatchPath(sourcePath).concat("metadata"),
5421
5520
  value: {
5521
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5522
+ ...currentValue.metadata,
5422
5523
  ...(fileMetadata.mimeType ? {
5423
5524
  mimeType: fileMetadata.mimeType
5424
5525
  } : {})
@@ -5452,21 +5553,6 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
5452
5553
  }
5453
5554
  });
5454
5555
  }
5455
- } else if (fix === "fix:deprecated-richtext") {
5456
- if (!validationError.value) {
5457
- throw Error("Cannot fix richtext without a value");
5458
- }
5459
- patch.push({
5460
- op: "replace",
5461
- path: sourceToPatchPath(sourcePath),
5462
- value: validationError.value
5463
- });
5464
- } else {
5465
- remainingErrors.push({
5466
- ...validationError,
5467
- message: `Unknown fix: ${fix}`,
5468
- fixes: undefined
5469
- });
5470
5556
  }
5471
5557
  }
5472
5558
  if (!validationError.fixes || validationError.fixes.length === 0) {
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.66.0",
15
+ "version": "0.67.1",
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.66.0",
27
- "@valbuild/shared": "~0.66.0",
28
- "@valbuild/ui": "~0.66.0",
26
+ "@valbuild/core": "~0.67.1",
27
+ "@valbuild/shared": "~0.67.1",
28
+ "@valbuild/ui": "~0.67.1",
29
29
  "chokidar": "^4.0.1",
30
30
  "image-size": "^1.0.2",
31
31
  "minimatch": "^3.0.4",