codama-renderers-dart 0.4.2 → 0.5.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.
@@ -3,7 +3,7 @@ import { join, dirname, posix } from 'path';
3
3
  import { staticVisitor, extendVisitor, visit, NodeStack, LinkableDictionary, pipe, recordNodeStackVisitor, recordLinkablesOnFirstVisitVisitor, rootNodeVisitor } from '@codama/visitors-core';
4
4
  import { createRenderMap, addToRenderMap, mergeRenderMaps, deleteDirectory } from '@codama/renderers-core';
5
5
  import { execSync } from 'child_process';
6
- import { resolveNestedTypeNode } from '@codama/nodes';
6
+ import { resolveNestedTypeNode, getAllInstructionsWithSubs } from '@codama/nodes';
7
7
  import { CodamaError, CODAMA_ERROR__UNEXPECTED_NODE_KIND } from '@codama/errors';
8
8
 
9
9
  // src/visitors/renderVisitor.ts
@@ -46,7 +46,7 @@ function createDartNameApi() {
46
46
  errorConstant: (programName, errorName) => `${camelCase(programName)}Error${pascalCase(errorName)}`,
47
47
  errorMessageFunction: (name) => `get${pascalCase(name)}ErrorMessage`,
48
48
  enumVariant: (name) => camelCase(name),
49
- sealedClassVariant: (_parentName, variantName) => pascalCase(variantName),
49
+ sealedClassVariant: (parentName, variantName) => `${pascalCase(parentName)}${pascalCase(variantName)}`,
50
50
  isTypeFunction: (name) => `is${pascalCase(name)}`,
51
51
  fileName: (name) => snakeCase(name),
52
52
  discriminatorConstant: (name) => `${camelCase(name)}Discriminator`
@@ -120,11 +120,16 @@ var DartImportMap = class {
120
120
  const uris = /* @__PURE__ */ new Set();
121
121
  for (const module of this._imports) {
122
122
  if (module in internalMap) {
123
- uris.add(internalMap[module]);
123
+ const uri = internalMap[module];
124
+ if (uri) {
125
+ uris.add(uri);
126
+ }
124
127
  } else if (module in DART_EXTERNAL_PACKAGE_MAP) {
125
128
  uris.add(DART_EXTERNAL_PACKAGE_MAP[module]);
126
- } else {
129
+ } else if (isRawDartImportUri(module)) {
127
130
  uris.add(module);
131
+ } else {
132
+ throw new Error(`Unresolved Dart import module "${module}"`);
128
133
  }
129
134
  }
130
135
  return [...uris].sort((a, b) => {
@@ -153,6 +158,9 @@ var DartImportMap = class {
153
158
  return lines.join("\n");
154
159
  }
155
160
  };
161
+ function isRawDartImportUri(module) {
162
+ return module.startsWith("dart:") || module.startsWith("package:") || module.endsWith(".dart") && !module.includes(":");
163
+ }
156
164
 
157
165
  // src/utils/fragment.ts
158
166
  function fragment(strings, ...values) {
@@ -244,10 +252,10 @@ var WELL_KNOWN_ADDRESSES = /* @__PURE__ */ new Map([
244
252
  ["Sysvar1111111111111111111111111111111111111", "sysvarOwnerAddress"],
245
253
  // SPL programs
246
254
  ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "tokenProgramAddress"],
247
- ["TokenzQdBNb4qyze1S1U9AHB8MGXmNK1REkTPT5Z3Y", "token2022ProgramAddress"],
248
- ["ATokenGPvbdGVxr1b2hvZbsiqW5xWH25ef7s3c8BnQKu", "associatedTokenProgramAddress"],
249
- ["Memo1UhkJRfRhVq1sR7Y7Nto1s3J2mXTT3L6Wk4K2m6", "memoProgramAddress"],
250
- ["MemoSq4gqABXKKYWVqKkV3m3kb1cTR7F2UMy9r6kFNK", "memoLegacyProgramAddress"],
255
+ ["TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb", "token2022ProgramAddress"],
256
+ ["ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", "associatedTokenProgramAddress"],
257
+ ["MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr", "memoProgramAddress"],
258
+ ["Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo", "memoLegacyProgramAddress"],
251
259
  // Metaplex programs
252
260
  ["metaqbxxU9qX8rZXkmUJ7haCrXXz2W1PSUq1Rn3E1od", "tokenMetadataProgramAddress"],
253
261
  ["BGUMAp9V1mQ2KV8t34L5u3gZsXYZaYDBdKkc1xYk1qA1", "mplBubblegumProgramAddress"],
@@ -402,17 +410,18 @@ function getTypeManifestVisitor(input) {
402
410
  },
403
411
  visitArrayType(node, { self }) {
404
412
  const itemManifest = visit(node.item, self);
405
- const sizeExpr = getArraySizeExpression(node);
413
+ const encoderSizeExpr = getArraySizeExpression(node, "Encoder");
414
+ const decoderSizeExpr = getArraySizeExpression(node, "Decoder");
406
415
  return {
407
416
  type: fragment`List<${itemManifest.type}>`,
408
417
  encoder: fragment`${use(
409
418
  "getArrayEncoder",
410
419
  "solanaCodecsDataStructures"
411
- )}(${itemManifest.encoder}${sizeExpr})`,
420
+ )}(${itemManifest.encoder}${encoderSizeExpr})`,
412
421
  decoder: fragment`${use(
413
422
  "getArrayDecoder",
414
423
  "solanaCodecsDataStructures"
415
- )}(${itemManifest.decoder}${sizeExpr})`,
424
+ )}(${itemManifest.decoder}${decoderSizeExpr})`,
416
425
  value: emptyTypeManifest().value,
417
426
  isEnum: false
418
427
  };
@@ -420,34 +429,36 @@ function getTypeManifestVisitor(input) {
420
429
  visitMapType(node, { self }) {
421
430
  const keyManifest = visit(node.key, self);
422
431
  const valueManifest = visit(node.value, self);
423
- const sizeExpr = getMapSizeExpression(node);
432
+ const encoderSizeExpr = getMapSizeExpression(node, "Encoder");
433
+ const decoderSizeExpr = getMapSizeExpression(node, "Decoder");
424
434
  return {
425
435
  type: fragment`Map<${keyManifest.type}, ${valueManifest.type}>`,
426
436
  encoder: fragment`${use(
427
437
  "getMapEncoder",
428
438
  "solanaCodecsDataStructures"
429
- )}(${keyManifest.encoder}, ${valueManifest.encoder}${sizeExpr})`,
439
+ )}(${keyManifest.encoder}, ${valueManifest.encoder}${encoderSizeExpr})`,
430
440
  decoder: fragment`${use(
431
441
  "getMapDecoder",
432
442
  "solanaCodecsDataStructures"
433
- )}(${keyManifest.decoder}, ${valueManifest.decoder}${sizeExpr})`,
443
+ )}(${keyManifest.decoder}, ${valueManifest.decoder}${decoderSizeExpr})`,
434
444
  value: emptyTypeManifest().value,
435
445
  isEnum: false
436
446
  };
437
447
  },
438
448
  visitSetType(node, { self }) {
439
449
  const itemManifest = visit(node.item, self);
440
- const sizeExpr = getSetSizeExpression(node);
450
+ const encoderSizeExpr = getSetSizeExpression(node, "Encoder");
451
+ const decoderSizeExpr = getSetSizeExpression(node, "Decoder");
441
452
  return {
442
453
  type: fragment`Set<${itemManifest.type}>`,
443
454
  encoder: fragment`${use(
444
455
  "getSetEncoder",
445
456
  "solanaCodecsDataStructures"
446
- )}(${itemManifest.encoder}${sizeExpr})`,
457
+ )}(${itemManifest.encoder}${encoderSizeExpr})`,
447
458
  decoder: fragment`${use(
448
459
  "getSetDecoder",
449
460
  "solanaCodecsDataStructures"
450
- )}(${itemManifest.decoder}${sizeExpr})`,
461
+ )}(${itemManifest.decoder}${decoderSizeExpr})`,
451
462
  value: emptyTypeManifest().value,
452
463
  isEnum: false
453
464
  };
@@ -623,9 +634,10 @@ function getTypeManifestVisitor(input) {
623
634
  const bigIntFormats = /* @__PURE__ */ new Set(["u64", "u128", "i64", "i128"]);
624
635
  let prefixManifest;
625
636
  if (node.prefix.kind === "numberTypeNode" && bigIntFormats.has(node.prefix.format)) {
637
+ const codecName = getNumberCodecName(node.prefix.format);
626
638
  prefixManifest = {
627
- encoder: fragment`${use("getU32Encoder", "solanaCodecsNumbers")}()`,
628
- decoder: fragment`${use("getU32Decoder", "solanaCodecsNumbers")}()`
639
+ encoder: fragment`transformEncoder(${use(`get${codecName}Encoder`, "solanaCodecsNumbers")}(), (size) => BigInt.from(size))`,
640
+ decoder: fragment`transformDecoder(${use(`get${codecName}Decoder`, "solanaCodecsNumbers")}(), (size, _, __) => size.toInt())`
629
641
  };
630
642
  } else {
631
643
  prefixManifest = visit(node.prefix, self);
@@ -812,7 +824,7 @@ function getNumberCodecExpression(format, codecType) {
812
824
  const name = getNumberCodecName(format);
813
825
  return `get${name}${codecType}()`;
814
826
  }
815
- function getArraySizeExpression(node) {
827
+ function getArraySizeExpression(node, codecType) {
816
828
  if (!("count" in node) || !node.count) return "";
817
829
  const count = node.count;
818
830
  switch (count.kind) {
@@ -825,13 +837,13 @@ function getArraySizeExpression(node) {
825
837
  if (resolvedPrefix.format === "u32" && (!resolvedPrefix.endian || resolvedPrefix.endian === "le")) {
826
838
  return "";
827
839
  }
828
- return `, size: PrefixedArraySize(get${getNumberCodecName(resolvedPrefix.format)}Encoder())`;
840
+ return `, size: PrefixedArraySize(${getNumberCodecExpression(resolvedPrefix.format, codecType)})`;
829
841
  }
830
842
  default:
831
843
  return "";
832
844
  }
833
845
  }
834
- function getMapSizeExpression(node) {
846
+ function getMapSizeExpression(node, codecType) {
835
847
  if (!("count" in node) || !node.count) return "";
836
848
  const count = node.count;
837
849
  switch (count.kind) {
@@ -844,13 +856,13 @@ function getMapSizeExpression(node) {
844
856
  if (resolvedPrefix.format === "u32" && (!resolvedPrefix.endian || resolvedPrefix.endian === "le")) {
845
857
  return "";
846
858
  }
847
- return `, size: PrefixedArraySize(get${getNumberCodecName(resolvedPrefix.format)}Encoder())`;
859
+ return `, size: PrefixedArraySize(${getNumberCodecExpression(resolvedPrefix.format, codecType)})`;
848
860
  }
849
861
  default:
850
862
  return "";
851
863
  }
852
864
  }
853
- function getSetSizeExpression(node) {
865
+ function getSetSizeExpression(node, codecType) {
854
866
  if (!("count" in node) || !node.count) return "";
855
867
  const count = node.count;
856
868
  switch (count.kind) {
@@ -863,7 +875,7 @@ function getSetSizeExpression(node) {
863
875
  if (resolvedPrefix.format === "u32" && (!resolvedPrefix.endian || resolvedPrefix.endian === "le")) {
864
876
  return "";
865
877
  }
866
- return `, size: PrefixedArraySize(get${getNumberCodecName(resolvedPrefix.format)}Encoder())`;
878
+ return `, size: PrefixedArraySize(${getNumberCodecExpression(resolvedPrefix.format, codecType)})`;
867
879
  }
868
880
  default:
869
881
  return "";
@@ -1234,7 +1246,7 @@ function getInstructionPageFragment(node, scope) {
1234
1246
  const manifest = argManifestMap.get(arg);
1235
1247
  const fieldName = camelCase(arg.name);
1236
1248
  const typeStr = manifest.type.content;
1237
- const hasDefault = arg.defaultValue != null;
1249
+ const hasDefault = arg.defaultValue != null && arg.defaultValue.kind !== "accountBumpValueNode";
1238
1250
  if (hasDefault) {
1239
1251
  const nullableType = typeStr.endsWith("?") ? typeStr : `${typeStr}?`;
1240
1252
  return ` ${nullableType} ${fieldName},`;
@@ -1255,7 +1267,9 @@ function getInstructionPageFragment(node, scope) {
1255
1267
  if (isDiscriminatorArg(arg, node)) {
1256
1268
  return "";
1257
1269
  }
1258
- return ` ${fieldName}: ${fieldName}${arg.defaultValue != null ? ` ?? ${getDefaultValue(arg)}` : ""},`;
1270
+ const typeStr2 = argManifestMap.get(arg)?.type.content;
1271
+ const skipDefault = arg.defaultValue?.kind === "accountBumpValueNode";
1272
+ return ` ${fieldName}: ${fieldName}${arg.defaultValue != null && !skipDefault ? ` ?? ${getDefaultValue(arg, typeStr2)}` : ""},`;
1259
1273
  }).filter(Boolean).join("\n");
1260
1274
  const discFragment = getDiscriminatorConstantsFragment(node, scope);
1261
1275
  const parts = [
@@ -1389,12 +1403,13 @@ function isConstDefaultValue(defaultValue) {
1389
1403
  return false;
1390
1404
  }
1391
1405
  }
1392
- function getDefaultValue(arg) {
1406
+ function getDefaultValue(arg, typeStr) {
1393
1407
  if (!arg.defaultValue) return "null";
1408
+ const isBigInt = typeStr === "BigInt";
1394
1409
  const dv = arg.defaultValue;
1395
1410
  switch (dv.kind) {
1396
1411
  case "numberValueNode":
1397
- return String(dv.number);
1412
+ return isBigInt ? `BigInt.from(${dv.number})` : String(dv.number);
1398
1413
  case "booleanValueNode":
1399
1414
  return String(dv.boolean);
1400
1415
  case "stringValueNode":
@@ -1534,8 +1549,6 @@ function bytesValueToDart(hex) {
1534
1549
  }
1535
1550
  return `[${pairs.join(", ")}]`;
1536
1551
  }
1537
-
1538
- // src/fragments/programPage.ts
1539
1552
  function getProgramPageFragment(node, scope) {
1540
1553
  const name = node.name;
1541
1554
  const addressConstName = scope.nameApi.programAddressConstant(name);
@@ -1567,17 +1580,146 @@ enum ${fragmentFromString(pascalCase(name))}Account {
1567
1580
  ${fragmentFromString(accountVariants)}
1568
1581
  }`);
1569
1582
  }
1570
- const instructions = node.instructions ?? [];
1583
+ const instructions = getAllInstructionsWithSubs(node);
1571
1584
  if (instructions.length > 0) {
1585
+ const programName = pascalCase(name);
1586
+ const instructionEnum = `${programName}Instruction`;
1572
1587
  const instrVariants = instructions.map((instr) => ` ${camelCase(instr.name)},`).join("\n");
1573
1588
  parts.push(fragment`
1574
- /// Known instructions for the ${fragmentFromString(pascalCase(name))} program.
1575
- enum ${fragmentFromString(pascalCase(name))}Instruction {
1589
+ /// Known instructions for the ${fragmentFromString(programName)} program.
1590
+ enum ${fragmentFromString(instructionEnum)} {
1576
1591
  ${fragmentFromString(instrVariants)}
1577
1592
  }`);
1593
+ const identifiableInstructions = instructions.map((instruction) => ({
1594
+ instruction,
1595
+ condition: getInstructionDiscriminatorCondition(instruction, scope)
1596
+ })).filter(({ condition }) => condition !== null);
1597
+ if (identifiableInstructions.length > 0) {
1598
+ const identifyBranches = identifiableInstructions.map(
1599
+ ({ instruction, condition }) => fragment` if (${condition}) {
1600
+ return ${fragmentFromString(instructionEnum)}.${fragmentFromString(camelCase(instruction.name))};
1601
+ }`
1602
+ );
1603
+ const parsedBase = `Parsed${programName}Instruction`;
1604
+ const parsedClasses = instructions.map((instruction) => {
1605
+ const instructionName = pascalCase(instruction.name);
1606
+ const variant = camelCase(instruction.name);
1607
+ const parsedClass = `Parsed${instructionName}`;
1608
+ const dataClass = `${instructionName}InstructionData`;
1609
+ return fragment`/// A parsed ${fragmentFromString(instructionName)} instruction.
1610
+ final class ${fragmentFromString(parsedClass)} extends ${fragmentFromString(parsedBase)} {
1611
+ const ${fragmentFromString(parsedClass)}({required this.data})
1612
+ : super(${fragmentFromString(instructionEnum)}.${fragmentFromString(variant)});
1613
+
1614
+ final ${use(dataClass, "../instructions/instructions.dart")} data;
1615
+ }`;
1616
+ });
1617
+ const parseBranches = instructions.map((instruction) => {
1618
+ const instructionName = pascalCase(instruction.name);
1619
+ const variant = camelCase(instruction.name);
1620
+ const parsedClass = `Parsed${instructionName}`;
1621
+ const parseFunction = scope.nameApi.instructionParseFunction(
1622
+ instruction.name
1623
+ );
1624
+ return fragment` ${fragmentFromString(instructionEnum)}.${fragmentFromString(variant)} => ${fragmentFromString(parsedClass)}(
1625
+ data: ${use(parseFunction, "../instructions/instructions.dart")}(instruction),
1626
+ ),`;
1627
+ });
1628
+ parts.push(fragment`
1629
+ /// Identifies the type of a ${fragmentFromString(programName)} instruction.
1630
+ ${fragmentFromString(instructionEnum)} identify${fragmentFromString(programName)}Instruction(
1631
+ ${use("Uint8List", "dartTypedData")} data,
1632
+ ) {
1633
+ ${mergeFragments(identifyBranches, (cs) => cs.join("\n"))}
1634
+
1635
+ throw ${use("SolanaError", "solanaErrors")}(
1636
+ ${use("SolanaErrorCode", "solanaErrors")}.programClientsFailedToIdentifyInstruction,
1637
+ {
1638
+ 'instructionData': data,
1639
+ 'programName': '${fragmentFromString(name)}',
1640
+ },
1641
+ );
1642
+ }
1643
+
1644
+ /// A parsed instruction from the ${fragmentFromString(programName)} program.
1645
+ sealed class ${fragmentFromString(parsedBase)} {
1646
+ const ${fragmentFromString(parsedBase)}(this.instructionType);
1647
+
1648
+ final ${fragmentFromString(instructionEnum)} instructionType;
1649
+ }
1650
+
1651
+ ${mergeFragments(parsedClasses, (cs) => cs.join("\n\n"))}
1652
+
1653
+ /// Parses a ${fragmentFromString(programName)} instruction.
1654
+ ${fragmentFromString(parsedBase)} parse${fragmentFromString(programName)}Instruction(
1655
+ ${use("Instruction", "solanaInstructions")} instruction,
1656
+ ) {
1657
+ return switch (identify${fragmentFromString(programName)}Instruction(
1658
+ instruction.data ?? Uint8List(0),
1659
+ )) {
1660
+ ${mergeFragments(parseBranches, (cs) => cs.join("\n"))}
1661
+ };
1662
+ }`);
1663
+ }
1578
1664
  }
1579
1665
  return mergeFragments(parts, (cs) => cs.join("\n"));
1580
1666
  }
1667
+ function getInstructionDiscriminatorCondition(instruction, scope) {
1668
+ const discriminators = instruction.discriminators ?? [];
1669
+ if (discriminators.length === 0) return null;
1670
+ const conditions = discriminators.map((discriminator) => {
1671
+ switch (discriminator.kind) {
1672
+ case "sizeDiscriminatorNode":
1673
+ return fragment`data.length == ${discriminator.size}`;
1674
+ case "constantDiscriminatorNode": {
1675
+ const manifest = visit(
1676
+ discriminator.constant.type,
1677
+ scope.typeManifestVisitor
1678
+ );
1679
+ const value = getValueFragment(
1680
+ discriminator.constant.value,
1681
+ manifest.type.content
1682
+ );
1683
+ if (value === null) return null;
1684
+ return fragment`${use("containsBytes", "solanaCodecsCore")}(data, ${manifest.encoder}.encode(${value}), ${discriminator.offset})`;
1685
+ }
1686
+ case "fieldDiscriminatorNode": {
1687
+ const argument = (instruction.arguments ?? []).find(
1688
+ (candidate) => candidate.name === discriminator.name
1689
+ );
1690
+ if (argument?.defaultValue == null) return null;
1691
+ const manifest = visit(argument.type, scope.typeManifestVisitor);
1692
+ const value = getValueFragment(
1693
+ argument.defaultValue,
1694
+ manifest.type.content
1695
+ );
1696
+ if (value === null) return null;
1697
+ return fragment`${use("containsBytes", "solanaCodecsCore")}(data, ${manifest.encoder}.encode(${value}), ${discriminator.offset})`;
1698
+ }
1699
+ }
1700
+ });
1701
+ if (conditions.some((condition) => condition === null)) return null;
1702
+ return mergeFragments(conditions, (cs) => cs.join(" && "));
1703
+ }
1704
+ function getValueFragment(value, dartType) {
1705
+ switch (value.kind) {
1706
+ case "numberValueNode":
1707
+ return fragmentFromString(
1708
+ dartType === "BigInt" ? `BigInt.from(${value.number})` : String(value.number)
1709
+ );
1710
+ case "booleanValueNode":
1711
+ return fragmentFromString(String(value.boolean));
1712
+ case "stringValueNode":
1713
+ return fragmentFromString(`'${value.string.replaceAll("'", "\\'")}'`);
1714
+ case "bytesValueNode": {
1715
+ const clean = value.data.replace(/^0x/, "");
1716
+ const bytes = clean.match(/.{1,2}/g)?.map((byte) => parseInt(byte, 16)) ?? [];
1717
+ return fragment`${use("Uint8List", "dartTypedData")}.fromList([${fragmentFromString(bytes.join(", "))}])`;
1718
+ }
1719
+ default:
1720
+ return null;
1721
+ }
1722
+ }
1581
1723
  function getTypePageFragment(node, scope) {
1582
1724
  const name = node.name;
1583
1725
  scope.nameApi.dataType(name);
@@ -1660,6 +1802,7 @@ function getDataEnumPageFragment(node, scope) {
1660
1802
  const allVariantManifests = [];
1661
1803
  for (let i = 0; i < enumNode.variants.length; i++) {
1662
1804
  const variant = enumNode.variants[i];
1805
+ const variantName = pascalCase(variant.name);
1663
1806
  const variantClassName = scope.nameApi.sealedClassVariant(
1664
1807
  name,
1665
1808
  variant.name
@@ -1676,7 +1819,7 @@ function getDataEnumPageFragment(node, scope) {
1676
1819
  int get hashCode => runtimeType.hashCode;
1677
1820
 
1678
1821
  @override
1679
- String toString() => '${typeName}.${variantClassName}()';
1822
+ String toString() => '${typeName}.${variantName}()';
1680
1823
  }`);
1681
1824
  encoderVariants.push(
1682
1825
  `(${i}, getStructEncoder(<(String, Encoder<Object?>)>[]))`
@@ -1723,7 +1866,7 @@ ${fieldDecls}
1723
1866
  int get hashCode => ${hashExpression};
1724
1867
 
1725
1868
  @override
1726
- String toString() => '${typeName}.${variantClassName}(${toStringFields})';
1869
+ String toString() => '${typeName}.${variantName}(${toStringFields})';
1727
1870
  }`);
1728
1871
  const encFields = fieldManifests.map(({ field: f, manifest }) => {
1729
1872
  return `('${f.name}', ${manifest.encoder.content})`;
@@ -1772,7 +1915,7 @@ ${fieldDecls}
1772
1915
  int get hashCode => value.hashCode;
1773
1916
 
1774
1917
  @override
1775
- String toString() => '${typeName}.${variantClassName}($value)';
1918
+ String toString() => '${typeName}.${variantName}($value)';
1776
1919
  }`);
1777
1920
  encoderVariants.push(
1778
1921
  `(${i}, transformEncoder<${manifest.type.content}, Map<String, Object?>>(${manifest.encoder.content}, (Map<String, Object?> map) => map['value']! as ${manifest.type.content}))`
@@ -2216,7 +2359,7 @@ function renderVisitor(outputDir, options = {}) {
2216
2359
  );
2217
2360
  const typePathMap = {};
2218
2361
  for (const renderPath of renderMap.keys()) {
2219
- const match = renderPath.match(/^(?:.*\/)?types\/([a-z_]+)\.dart$/);
2362
+ const match = renderPath.match(/^(?:.*\/)?types\/([a-z0-9_]+)\.dart$/);
2220
2363
  if (match) {
2221
2364
  typePathMap[`definedType:${match[1]}`] = renderPath;
2222
2365
  }
@@ -2230,7 +2373,10 @@ function renderVisitor(outputDir, options = {}) {
2230
2373
  const fileDir = dirname(filePath);
2231
2374
  const internalMap = {};
2232
2375
  for (const [key, typePath] of Object.entries(typePathMap)) {
2233
- if (typePath === filePath) continue;
2376
+ if (typePath === filePath) {
2377
+ internalMap[key] = "";
2378
+ continue;
2379
+ }
2234
2380
  let rel = posix.relative(fileDir, typePath);
2235
2381
  if (!rel.startsWith(".")) {
2236
2382
  rel = `./${rel}`;