codama-renderers-dart 0.5.3 → 0.5.5

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.
Files changed (35) hide show
  1. package/README.md +6 -0
  2. package/dist/index.browser.cjs +195 -126
  3. package/dist/index.browser.cjs.map +1 -1
  4. package/dist/index.browser.js +196 -127
  5. package/dist/index.browser.js.map +1 -1
  6. package/dist/index.node.cjs +195 -126
  7. package/dist/index.node.cjs.map +1 -1
  8. package/dist/index.node.js +196 -127
  9. package/dist/index.node.js.map +1 -1
  10. package/dist/index.react-native.js +196 -127
  11. package/dist/index.react-native.js.map +1 -1
  12. package/dist/types/fragments/accountPage.d.ts.map +1 -1
  13. package/dist/types/fragments/errorPage.d.ts.map +1 -1
  14. package/dist/types/fragments/instructionPage.d.ts.map +1 -1
  15. package/dist/types/fragments/pdaPage.d.ts.map +1 -1
  16. package/dist/types/fragments/programPage.d.ts.map +1 -1
  17. package/dist/types/utils/nameTransformers.d.ts.map +1 -1
  18. package/dist/types/utils/valueNodes.d.ts +4 -0
  19. package/dist/types/utils/valueNodes.d.ts.map +1 -1
  20. package/dist/types/visitors/getRenderMapVisitor.d.ts.map +1 -1
  21. package/dist/types/visitors/getTypeManifestVisitor.d.ts.map +1 -1
  22. package/dist/types/visitors/renderVisitor.d.ts.map +1 -1
  23. package/package.json +11 -11
  24. package/src/fragments/accountPage.ts +2 -1
  25. package/src/fragments/errorPage.ts +8 -5
  26. package/src/fragments/instructionPage.ts +51 -21
  27. package/src/fragments/pdaPage.ts +7 -14
  28. package/src/fragments/programPage.ts +3 -2
  29. package/src/utils/formatCode.ts +2 -2
  30. package/src/utils/nameTransformers.ts +11 -0
  31. package/src/utils/valueNodes.ts +24 -1
  32. package/src/visitors/getRenderMapVisitor.ts +30 -5
  33. package/src/visitors/getTypeManifestVisitor.ts +127 -87
  34. package/src/visitors/renderVisitor.ts +11 -13
  35. package/LICENSE +0 -21
@@ -5,6 +5,7 @@ import {
5
5
  type BooleanTypeNode,
6
6
  type BytesTypeNode,
7
7
  type CamelCaseString,
8
+ type ConstantValueNode,
8
9
  type DateTimeTypeNode,
9
10
  type DefinedTypeLinkNode,
10
11
  type DefinedTypeNode,
@@ -31,6 +32,7 @@ import {
31
32
  type StructFieldTypeNode,
32
33
  type StructTypeNode,
33
34
  type TupleTypeNode,
35
+ type TypeNode,
34
36
  type ZeroableOptionTypeNode,
35
37
  isNode,
36
38
  resolveNestedTypeNode,
@@ -55,6 +57,7 @@ import {
55
57
  use,
56
58
  } from "../utils/index.js";
57
59
  import { type DartNameApi, snakeCase } from "../utils/nameTransformers.js";
60
+ import { getDartValueFragment, getNonNegativeInteger, toDartStringLiteral } from "../utils/valueNodes.js";
58
61
 
59
62
  /**
60
63
  * Type alias for the type manifest visitor.
@@ -121,32 +124,12 @@ export function getTypeManifestVisitor(input: {
121
124
  );
122
125
 
123
126
  return extendVisitor(baseVisitor, {
124
- visitNumberType(node: NumberTypeNode, { self }) {
125
- const { format, endian } = node;
126
- const endianSuffix =
127
- endian === "be"
128
- ? ", NumberCodecConfig(endian: Endian.big)"
129
- : "";
130
- const endianDecoderSuffix =
131
- endian === "be"
132
- ? ", NumberCodecConfig(endian: Endian.big)"
133
- : "";
134
-
135
- // Map format to Dart type and codec
136
- const dartType = getNumberDartType(format);
137
- const codecName = getNumberCodecName(format);
138
-
127
+ visitNumberType(node: NumberTypeNode) {
139
128
  return {
140
129
  // `BigInt` and other number types live in `dart:core` and need no import.
141
- type: fragmentFromString(dartType),
142
- encoder: fragment`${use(
143
- `get${codecName}Encoder`,
144
- "solanaCodecsNumbers",
145
- )}(${endianSuffix ? fragmentFromString(endianSuffix.slice(2)) : fragmentFromString("")})`,
146
- decoder: fragment`${use(
147
- `get${codecName}Decoder`,
148
- "solanaCodecsNumbers",
149
- )}(${endianDecoderSuffix ? fragmentFromString(endianDecoderSuffix.slice(2)) : fragmentFromString("")})`,
130
+ type: fragmentFromString(getNumberDartType(node.format)),
131
+ encoder: getNumberCodecExpression(node, "Encoder"),
132
+ decoder: getNumberCodecExpression(node, "Decoder"),
150
133
  value: emptyTypeManifest().value,
151
134
  isEnum: false,
152
135
  };
@@ -226,8 +209,8 @@ export function getTypeManifestVisitor(input: {
226
209
 
227
210
  visitArrayType(node: ArrayTypeNode, { self }) {
228
211
  const itemManifest = visit(node.item, self);
229
- const encoderSizeExpr = getArraySizeExpression(node, "Encoder");
230
- const decoderSizeExpr = getArraySizeExpression(node, "Decoder");
212
+ const encoderSizeExpr = getArraySizeExpression(node, "Encoder", self);
213
+ const decoderSizeExpr = getArraySizeExpression(node, "Decoder", self);
231
214
  const itemType = fragmentFromString(itemManifest.type.content);
232
215
  const itemEncoder = fragment`${use(
233
216
  "transformEncoder",
@@ -252,8 +235,8 @@ export function getTypeManifestVisitor(input: {
252
235
  visitMapType(node: MapTypeNode, { self }) {
253
236
  const keyManifest = visit(node.key, self);
254
237
  const valueManifest = visit(node.value, self);
255
- const encoderSizeExpr = getMapSizeExpression(node, "Encoder");
256
- const decoderSizeExpr = getMapSizeExpression(node, "Decoder");
238
+ const encoderSizeExpr = getMapSizeExpression(node, "Encoder", self);
239
+ const decoderSizeExpr = getMapSizeExpression(node, "Decoder", self);
257
240
 
258
241
  return {
259
242
  type: fragment`Map<${keyManifest.type}, ${valueManifest.type}>`,
@@ -272,8 +255,8 @@ export function getTypeManifestVisitor(input: {
272
255
 
273
256
  visitSetType(node: SetTypeNode, { self }) {
274
257
  const itemManifest = visit(node.item, self);
275
- const encoderSizeExpr = getSetSizeExpression(node, "Encoder");
276
- const decoderSizeExpr = getSetSizeExpression(node, "Decoder");
258
+ const encoderSizeExpr = getSetSizeExpression(node, "Encoder", self);
259
+ const decoderSizeExpr = getSetSizeExpression(node, "Decoder", self);
277
260
 
278
261
  return {
279
262
  type: fragment`Set<${itemManifest.type}>`,
@@ -355,7 +338,7 @@ export function getTypeManifestVisitor(input: {
355
338
 
356
339
  // Build encoder fields list
357
340
  const encoderFields = fields
358
- .map((f, i) => `('${fieldNames[i]}', ${f.encoder.content})`)
341
+ .map((f, i) => `(${toDartStringLiteral(fieldNames[i])}, ${f.encoder.content})`)
359
342
  .join(", ");
360
343
  const encoderFrag = fragment`${use(
361
344
  "getStructEncoder",
@@ -366,7 +349,7 @@ export function getTypeManifestVisitor(input: {
366
349
  }
367
350
 
368
351
  const decoderFields = fields
369
- .map((f, i) => `('${fieldNames[i]}', ${f.decoder.content})`)
352
+ .map((f, i) => `(${toDartStringLiteral(fieldNames[i])}, ${f.decoder.content})`)
370
353
  .join(", ");
371
354
  const decoderFrag = fragment`${use(
372
355
  "getStructDecoder",
@@ -442,10 +425,10 @@ export function getTypeManifestVisitor(input: {
442
425
  const itemTypeStr = itemManifest.type.content;
443
426
  const resolvedPrefix = resolveNestedTypeNode(node.prefix);
444
427
  const prefixExpr = resolvedPrefix.format !== "u8"
445
- ? `, prefix: ${getNumberCodecExpression(resolvedPrefix.format, "Encoder")}`
428
+ ? fragment`, prefix: ${getNumberCodecExpression(resolvedPrefix, "Encoder")}`
446
429
  : "";
447
430
  const prefixDecoderExpr = resolvedPrefix.format !== "u8"
448
- ? `, prefix: ${getNumberCodecExpression(resolvedPrefix.format, "Decoder")}`
431
+ ? fragment`, prefix: ${getNumberCodecExpression(resolvedPrefix, "Decoder")}`
449
432
  : "";
450
433
  const noneValueExpr = node.fixed
451
434
  ? ", noneValue: const ZeroesNoneValue()"
@@ -459,11 +442,11 @@ export function getTypeManifestVisitor(input: {
459
442
  )}<${fragmentFromString(itemTypeStr)}>(${use(
460
443
  "transformEncoder",
461
444
  "solanaCodecsCore",
462
- )}(${itemManifest.encoder}, (${fragmentFromString(itemTypeStr)} value) => value)${fragmentFromString(prefixExpr)}${fragmentFromString(noneValueExpr)})`,
445
+ )}(${itemManifest.encoder}, (${fragmentFromString(itemTypeStr)} value) => value)${prefixExpr}${fragmentFromString(noneValueExpr)})`,
463
446
  decoder: fragment`${use(
464
447
  "getNullableDecoder",
465
448
  "solanaCodecsDataStructures",
466
- )}<${fragmentFromString(itemTypeStr)}>(${itemManifest.decoder}${fragmentFromString(prefixDecoderExpr)}${fragmentFromString(noneValueExpr)})`,
449
+ )}<${fragmentFromString(itemTypeStr)}>(${itemManifest.decoder}${prefixDecoderExpr}${fragmentFromString(noneValueExpr)})`,
467
450
  value: emptyTypeManifest().value,
468
451
  isEnum: false,
469
452
  };
@@ -521,11 +504,11 @@ export function getTypeManifestVisitor(input: {
521
504
  encoder: fragment`${use(
522
505
  "fixEncoderSize",
523
506
  "solanaCodecsCore",
524
- )}(${innerManifest.encoder}, ${fragmentFromString(String(node.size))}, allowTruncation: false)`,
507
+ )}(${innerManifest.encoder}, ${fragmentFromString(getNonNegativeInteger(node.size))}, allowTruncation: false)`,
525
508
  decoder: fragment`${use(
526
509
  "fixDecoderSize",
527
510
  "solanaCodecsCore",
528
- )}(${innerManifest.decoder}, ${fragmentFromString(String(node.size))})`,
511
+ )}(${innerManifest.decoder}, ${fragmentFromString(getNonNegativeInteger(node.size))})`,
529
512
  value: innerManifest.value,
530
513
  isEnum: innerManifest.isEnum,
531
514
  };
@@ -544,12 +527,12 @@ export function getTypeManifestVisitor(input: {
544
527
  let prefixManifest;
545
528
  if (
546
529
  node.prefix.kind === "numberTypeNode" &&
547
- bigIntFormats.has((node.prefix as any).format)
530
+ bigIntFormats.has(node.prefix.format)
548
531
  ) {
549
- const codecName = getNumberCodecName((node.prefix as any).format);
532
+ const numberManifest = visit(node.prefix, self);
550
533
  prefixManifest = {
551
- encoder: fragment`transformEncoder(${use(`get${codecName}Encoder`, "solanaCodecsNumbers")}(), (size) => BigInt.from(size))`,
552
- decoder: fragment`transformDecoder(${use(`get${codecName}Decoder`, "solanaCodecsNumbers")}(), (size, _, __) => size.toInt())`,
534
+ encoder: fragment`${use("transformEncoder", "solanaCodecsCore")}(${numberManifest.encoder}, (size) => BigInt.from(size))`,
535
+ decoder: fragment`${use("transformDecoder", "solanaCodecsCore")}(${numberManifest.decoder}, (size, _, __) => size.toInt())`,
553
536
  };
554
537
  } else {
555
538
  prefixManifest = visit(node.prefix, self);
@@ -660,13 +643,11 @@ export function getTypeManifestVisitor(input: {
660
643
  },
661
644
 
662
645
  visitPreOffsetType(node: PreOffsetTypeNode, { self }) {
663
- // Pre-offset types pass through to inner type in Dart
664
- return visit(node.type, self);
646
+ return getOffsetManifest(node, self);
665
647
  },
666
648
 
667
649
  visitPostOffsetType(node: PostOffsetTypeNode, { self }) {
668
- // Post-offset types pass through to inner type in Dart
669
- return visit(node.type, self);
650
+ return getOffsetManifest(node, self);
670
651
  },
671
652
 
672
653
  visitSolAmountType(node: SolAmountTypeNode, { self }) {
@@ -777,30 +758,39 @@ function getNumberCodecName(format: string): string {
777
758
  }
778
759
 
779
760
  function getNumberCodecExpression(
780
- format: string,
761
+ node: NumberTypeNode,
781
762
  codecType: "Encoder" | "Decoder",
782
- ): string {
783
- const name = getNumberCodecName(format);
784
- return `get${name}${codecType}()`;
763
+ ): Fragment {
764
+ const name = getNumberCodecName(node.format);
765
+ const config = node.endian === "be"
766
+ ? fragment`${use("NumberCodecConfig", "solanaCodecsNumbers")}(endian: ${use("Endian", "dartTypedData")}.big)`
767
+ : "";
768
+
769
+ return fragment`${use(`get${name}${codecType}`, "solanaCodecsNumbers")}(${config})`;
785
770
  }
786
771
 
787
772
  function getArraySizeExpression(
788
773
  node: ArrayTypeNode,
789
774
  codecType: "Encoder" | "Decoder",
790
- ): string {
775
+ self: Visitor<TypeManifest>,
776
+ ): string | Fragment {
791
777
  if (!("count" in node) || !node.count) return "";
792
778
  const count = node.count;
793
779
  switch (count.kind) {
794
780
  case "fixedCountNode":
795
- return `, size: FixedArraySize(${count.value})`;
781
+ return `, size: FixedArraySize(${getNonNegativeInteger(count.value)})`;
796
782
  case "remainderCountNode":
797
783
  return ", size: RemainderArraySize()";
798
784
  case "prefixedCountNode": {
799
- const resolvedPrefix = resolveNestedTypeNode(count.prefix);
800
- if (resolvedPrefix.format === "u32" && (!resolvedPrefix.endian || resolvedPrefix.endian === "le")) {
785
+ if (
786
+ count.prefix.kind === "numberTypeNode" &&
787
+ count.prefix.format === "u32" &&
788
+ (!count.prefix.endian || count.prefix.endian === "le")
789
+ ) {
801
790
  return ""; // Default
802
791
  }
803
- return `, size: PrefixedArraySize(${getNumberCodecExpression(resolvedPrefix.format, codecType)})`;
792
+ const prefix = visit(count.prefix, self);
793
+ return fragment`, size: PrefixedArraySize(${codecType === "Encoder" ? prefix.encoder : prefix.decoder})`;
804
794
  }
805
795
  default:
806
796
  return "";
@@ -810,20 +800,25 @@ function getArraySizeExpression(
810
800
  function getMapSizeExpression(
811
801
  node: MapTypeNode,
812
802
  codecType: "Encoder" | "Decoder",
813
- ): string {
803
+ self: Visitor<TypeManifest>,
804
+ ): string | Fragment {
814
805
  if (!("count" in node) || !node.count) return "";
815
806
  const count = node.count;
816
807
  switch (count.kind) {
817
808
  case "fixedCountNode":
818
- return `, size: FixedArraySize(${count.value})`;
809
+ return `, size: FixedArraySize(${getNonNegativeInteger(count.value)})`;
819
810
  case "remainderCountNode":
820
811
  return ", size: RemainderArraySize()";
821
812
  case "prefixedCountNode": {
822
- const resolvedPrefix = resolveNestedTypeNode(count.prefix);
823
- if (resolvedPrefix.format === "u32" && (!resolvedPrefix.endian || resolvedPrefix.endian === "le")) {
813
+ if (
814
+ count.prefix.kind === "numberTypeNode" &&
815
+ count.prefix.format === "u32" &&
816
+ (!count.prefix.endian || count.prefix.endian === "le")
817
+ ) {
824
818
  return "";
825
819
  }
826
- return `, size: PrefixedArraySize(${getNumberCodecExpression(resolvedPrefix.format, codecType)})`;
820
+ const prefix = visit(count.prefix, self);
821
+ return fragment`, size: PrefixedArraySize(${codecType === "Encoder" ? prefix.encoder : prefix.decoder})`;
827
822
  }
828
823
  default:
829
824
  return "";
@@ -833,20 +828,25 @@ function getMapSizeExpression(
833
828
  function getSetSizeExpression(
834
829
  node: SetTypeNode,
835
830
  codecType: "Encoder" | "Decoder",
836
- ): string {
831
+ self: Visitor<TypeManifest>,
832
+ ): string | Fragment {
837
833
  if (!("count" in node) || !node.count) return "";
838
834
  const count = node.count;
839
835
  switch (count.kind) {
840
836
  case "fixedCountNode":
841
- return `, size: FixedArraySize(${count.value})`;
837
+ return `, size: FixedArraySize(${getNonNegativeInteger(count.value)})`;
842
838
  case "remainderCountNode":
843
839
  return ", size: RemainderArraySize()";
844
840
  case "prefixedCountNode": {
845
- const resolvedPrefix = resolveNestedTypeNode(count.prefix);
846
- if (resolvedPrefix.format === "u32" && (!resolvedPrefix.endian || resolvedPrefix.endian === "le")) {
841
+ if (
842
+ count.prefix.kind === "numberTypeNode" &&
843
+ count.prefix.format === "u32" &&
844
+ (!count.prefix.endian || count.prefix.endian === "le")
845
+ ) {
847
846
  return "";
848
847
  }
849
- return `, size: PrefixedArraySize(${getNumberCodecExpression(resolvedPrefix.format, codecType)})`;
848
+ const prefix = visit(count.prefix, self);
849
+ return fragment`, size: PrefixedArraySize(${codecType === "Encoder" ? prefix.encoder : prefix.decoder})`;
850
850
  }
851
851
  default:
852
852
  return "";
@@ -859,7 +859,7 @@ type HiddenAffixManifest = {
859
859
  };
860
860
 
861
861
  function getHiddenAffixManifest(
862
- node: any,
862
+ node: ConstantValueNode | TypeNode,
863
863
  self: Visitor<TypeManifest>,
864
864
  ): HiddenAffixManifest {
865
865
  if (node?.kind !== "constantValueNode") {
@@ -867,40 +867,80 @@ function getHiddenAffixManifest(
867
867
  return { encoder: manifest.encoder, decoder: manifest.decoder };
868
868
  }
869
869
 
870
- const constantBytes = getConstantBytesExpression(node);
870
+ const constantBytes = getConstantBytesExpression(node, self);
871
871
  return {
872
872
  encoder: fragment`${use("getConstantEncoder", "solanaCodecsDataStructures")}(${constantBytes})`,
873
873
  decoder: fragment`${use("getConstantDecoder", "solanaCodecsDataStructures")}(${constantBytes})`,
874
874
  };
875
875
  }
876
876
 
877
- function getConstantBytesExpression(node: any): Fragment {
878
- const valueNode = node.value;
879
- const typeNode = node.type;
880
-
881
- if (valueNode?.kind !== "numberValueNode") {
877
+ /** Serialize affix constants using the same validated codec as ordinary fields. */
878
+ function getConstantBytesExpression(
879
+ node: ConstantValueNode,
880
+ self: Visitor<TypeManifest>,
881
+ ): Fragment {
882
+ if (node.value.kind !== "numberValueNode") {
882
883
  throw new Error(
883
- `Unsupported hidden affix constant value kind: ${valueNode?.kind}`,
884
+ `Unsupported hidden affix constant value kind: ${node.value.kind}`,
884
885
  );
885
886
  }
886
887
 
887
- const value = Number(valueNode.number);
888
+ const manifest = visit(node.type, self);
888
889
 
889
- if (typeNode?.kind === "numberTypeNode") {
890
- return fragment`${use(`get${getNumberCodecName(typeNode.format)}Encoder`, "solanaCodecsNumbers")}().encode(${value})`;
890
+ if (!["int", "BigInt", "double"].includes(manifest.type.content)) {
891
+ throw new Error(`Unsupported hidden affix constant type kind: ${node.type.kind}`);
891
892
  }
892
893
 
893
- if (typeNode?.kind === "preOffsetTypeNode") {
894
- const inner = typeNode.type;
895
- if (inner?.kind !== "numberTypeNode") {
896
- throw new Error(
897
- `Unsupported hidden affix pre-offset inner type kind: ${inner?.kind}`,
898
- );
899
- }
900
- return fragment`${use("padLeftEncoder", "solanaCodecsCore")}(${use(`get${getNumberCodecName(inner.format)}Encoder`, "solanaCodecsNumbers")}(), ${typeNode.offset}).encode(${value})`;
894
+ const value = getDartValueFragment(node.value, manifest.type.content);
895
+
896
+ return fragment`${manifest.encoder}.encode(${value})`;
897
+ }
898
+
899
+ /** Preserve the IDL's cursor strategy instead of silently discarding offsets. */
900
+ function getOffsetManifest(
901
+ node: PreOffsetTypeNode | PostOffsetTypeNode,
902
+ self: Visitor<TypeManifest>,
903
+ ): TypeManifest {
904
+ if (!Number.isSafeInteger(node.offset)) {
905
+ throw new Error("Expected a safe integer for a codec offset");
901
906
  }
902
907
 
903
- throw new Error(
904
- `Unsupported hidden affix constant type kind: ${typeNode?.kind}`,
905
- );
908
+ const manifest = visit(node.type, self);
909
+ const pre = node.kind === "preOffsetTypeNode";
910
+ const key = pre ? "preOffset" : "postOffset";
911
+
912
+ if (node.strategy === "padded") {
913
+ const side = pre ? "Left" : "Right";
914
+ const offset = getNonNegativeInteger(node.offset);
915
+
916
+ return {
917
+ ...manifest,
918
+ encoder: fragment`${use(`pad${side}Encoder`, "solanaCodecsCore")}(${manifest.encoder}, ${offset})`,
919
+ decoder: fragment`${use(`pad${side}Decoder`, "solanaCodecsCore")}(${manifest.decoder}, ${offset})`,
920
+ };
921
+ }
922
+
923
+ let expression: string;
924
+
925
+ switch (node.strategy) {
926
+ case "absolute":
927
+ expression = node.offset < 0 ? `scope.wrapBytes(${node.offset})` : String(node.offset);
928
+ break;
929
+ case "relative":
930
+ expression = `scope.${key} + ${node.offset}`;
931
+ break;
932
+ case "preOffset":
933
+ expression = `scope.preOffset + ${node.offset}`;
934
+ break;
935
+ default:
936
+ throw new Error(`Unsupported offset strategy: ${node.strategy}`);
937
+ }
938
+
939
+ const config = fragment`${use("OffsetConfig", "solanaCodecsCore")}(${key}: (scope) => ${expression})`;
940
+
941
+ return {
942
+ ...manifest,
943
+ encoder: fragment`${use("offsetEncoder", "solanaCodecsCore")}(${manifest.encoder}, ${config})`,
944
+ decoder: fragment`${use("offsetDecoder", "solanaCodecsCore")}(${manifest.decoder}, ${config})`,
945
+ };
906
946
  }
@@ -32,11 +32,6 @@ export function renderVisitor(
32
32
  return rootNodeVisitor((root: RootNode) => {
33
33
  const normalizedRoot = normalizeRootNode(root);
34
34
 
35
- // 1. Optionally delete the output directory
36
- if (deleteFolderBeforeRendering && existsSync(outputDir)) {
37
- deleteDirectory(outputDir);
38
- }
39
-
40
35
  // 2. Build the render map
41
36
  const renderMap = visit(
42
37
  normalizedRoot,
@@ -52,16 +47,10 @@ export function renderVisitor(
52
47
  }
53
48
  }
54
49
 
55
- // 4. Resolve imports and write files
50
+ // Resolve every file before deleting previous output, so invalid IDLs fail safely.
51
+ const files: [string, string][] = [];
56
52
  for (const [filePath, frag] of renderMap.entries()) {
57
53
  const fullPath = join(outputDir, filePath);
58
- const dir = dirname(fullPath);
59
-
60
- // Ensure directory exists
61
- if (!existsSync(dir)) {
62
- mkdirSync(dir, { recursive: true });
63
- }
64
-
65
54
  // Compute per-file internal import map (relative paths to defined types)
66
55
  const fileDir = dirname(filePath);
67
56
  const internalMap: Record<string, string> = {};
@@ -81,6 +70,15 @@ export function renderVisitor(
81
70
 
82
71
  // Resolve fragment content with imports
83
72
  const content = resolveFragmentContent(frag, dependencyMap ?? {}, internalMap);
73
+ files.push([fullPath, content]);
74
+ }
75
+
76
+ if (deleteFolderBeforeRendering && existsSync(outputDir)) {
77
+ deleteDirectory(outputDir);
78
+ }
79
+
80
+ for (const [fullPath, content] of files) {
81
+ mkdirSync(dirname(fullPath), { recursive: true });
84
82
  writeFileSync(fullPath, content, "utf-8");
85
83
  }
86
84
 
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Ifiok Jr.
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.