codama-renderers-dart 0.5.1 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{readme.md → README.md} +16 -43
- package/dist/index.browser.cjs +345 -124
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.js +346 -125
- package/dist/index.browser.js.map +1 -1
- package/dist/index.node.cjs +345 -124
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.js +346 -125
- package/dist/index.node.js.map +1 -1
- package/dist/index.react-native.js +346 -125
- package/dist/index.react-native.js.map +1 -1
- package/dist/types/fragments/accountPage.d.ts.map +1 -1
- package/dist/types/fragments/errorPage.d.ts.map +1 -1
- package/dist/types/fragments/instructionPage.d.ts.map +1 -1
- package/dist/types/fragments/pdaPage.d.ts.map +1 -1
- package/dist/types/fragments/programPage.d.ts.map +1 -1
- package/dist/types/utils/nameTransformers.d.ts +5 -0
- package/dist/types/utils/nameTransformers.d.ts.map +1 -1
- package/dist/types/utils/valueNodes.d.ts +4 -0
- package/dist/types/utils/valueNodes.d.ts.map +1 -1
- package/dist/types/visitors/getRenderMapVisitor.d.ts.map +1 -1
- package/dist/types/visitors/getTypeManifestVisitor.d.ts +1 -1
- package/dist/types/visitors/getTypeManifestVisitor.d.ts.map +1 -1
- package/dist/types/visitors/renderVisitor.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/fragments/accountPage.ts +2 -1
- package/src/fragments/errorPage.ts +8 -5
- package/src/fragments/instructionPage.ts +54 -17
- package/src/fragments/pdaPage.ts +7 -14
- package/src/fragments/programPage.ts +3 -2
- package/src/fragments/typePage.ts +102 -19
- package/src/utils/formatCode.ts +2 -2
- package/src/utils/nameTransformers.ts +39 -1
- package/src/utils/valueNodes.ts +24 -1
- package/src/visitors/getRenderMapVisitor.ts +30 -5
- package/src/visitors/getTypeManifestVisitor.ts +123 -81
- package/src/visitors/renderVisitor.ts +11 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"accountPage.d.ts","sourceRoot":"","sources":["../../../src/fragments/accountPage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAuB,MAAM,eAAe,CAAC;AAItE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAQrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"accountPage.d.ts","sourceRoot":"","sources":["../../../src/fragments/accountPage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAuB,MAAM,eAAe,CAAC;AAItE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAQrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAWvD;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,WAAW,GACjB,QAAQ,CA8OV"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errorPage.d.ts","sourceRoot":"","sources":["../../../src/fragments/errorPage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"errorPage.d.ts","sourceRoot":"","sources":["../../../src/fragments/errorPage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AASrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGvD;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,WAAW,GACjB,QAAQ,CA2DV"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instructionPage.d.ts","sourceRoot":"","sources":["../../../src/fragments/instructionPage.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,eAAe,EAChB,MAAM,eAAe,CAAC;AAGvB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAOrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAUvD;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,eAAe,EACrB,KAAK,EAAE,WAAW,GACjB,QAAQ,
|
|
1
|
+
{"version":3,"file":"instructionPage.d.ts","sourceRoot":"","sources":["../../../src/fragments/instructionPage.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,eAAe,EAChB,MAAM,eAAe,CAAC;AAGvB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAOrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAUvD;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,eAAe,EACrB,KAAK,EAAE,WAAW,GACjB,QAAQ,CA+VV"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pdaPage.d.ts","sourceRoot":"","sources":["../../../src/fragments/pdaPage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAOrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"pdaPage.d.ts","sourceRoot":"","sources":["../../../src/fragments/pdaPage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAOrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAMvD;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,WAAW,GACjB,QAAQ,CAoJV"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"programPage.d.ts","sourceRoot":"","sources":["../../../src/fragments/programPage.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,WAAW,EAEjB,MAAM,eAAe,CAAC;AAGvB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAQrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"programPage.d.ts","sourceRoot":"","sources":["../../../src/fragments/programPage.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,WAAW,EAEjB,MAAM,eAAe,CAAC;AAGvB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAQrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAKvD;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,WAAW,GACjB,QAAQ,CAiJV"}
|
|
@@ -4,6 +4,11 @@ import type { CamelCaseString } from "@codama/nodes";
|
|
|
4
4
|
*/
|
|
5
5
|
/** Convert a string to PascalCase */
|
|
6
6
|
export declare function pascalCase(str: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Escape a lowercase identifier if it collides with a Dart reserved word
|
|
9
|
+
* by appending `_` (e.g. an account named `null` renders as `null_`).
|
|
10
|
+
*/
|
|
11
|
+
export declare function escapeDartIdentifier(name: string): string;
|
|
7
12
|
/** Convert a string to camelCase */
|
|
8
13
|
export declare function camelCase(str: string): string;
|
|
9
14
|
/** Convert a string to snake_case */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nameTransformers.d.ts","sourceRoot":"","sources":["../../../src/utils/nameTransformers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD;;GAEG;AAEH,qCAAqC;AACrC,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"nameTransformers.d.ts","sourceRoot":"","sources":["../../../src/utils/nameTransformers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD;;GAEG;AAEH,qCAAqC;AACrC,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM9C;AAoBD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,oCAAoC;AACpC,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI7C;AAED,qCAAqC;AACrC,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAS7C;AAED,+CAA+C;AAC/C,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,oCAAoC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,sDAAsD;IACtD,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtC,sDAAsD;IACtD,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtC,kDAAkD;IAClD,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACpC,kDAAkD;IAClD,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3C,6DAA6D;IAC7D,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAChD,oDAAoD;IACpD,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5C,+CAA+C;IAC/C,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1C,iDAAiD;IACjD,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtC,iEAAiE;IACjE,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1C,iEAAiE;IACjE,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/C,4DAA4D;IAC5D,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7C,4DAA4D;IAC5D,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9D,4DAA4D;IAC5D,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3C,gCAAgC;IAChC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAClC,mEAAmE;IACnE,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;IACpE,mCAAmC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,yDAAyD;IACzD,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5C,oDAAoD;IACpD,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CACtC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,WAAW,CAwB/C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,CAEhE"}
|
|
@@ -12,5 +12,9 @@ type RenderableValueNode = InstructionInputValueNode | ValueNode;
|
|
|
12
12
|
export declare function getDartValueFragment(value: RenderableValueNode, dartType?: string): Fragment;
|
|
13
13
|
/** Return whether a rendered standalone value is valid in a const initializer. */
|
|
14
14
|
export declare function isConstDartValueNode(value: RenderableValueNode): boolean;
|
|
15
|
+
/** Escape IDL text so it remains data inside a Dart string literal. */
|
|
16
|
+
export declare function toDartStringLiteral(value: string): string;
|
|
17
|
+
/** Reject executable or lossy sizes from serialized IDLs before generating Dart. */
|
|
18
|
+
export declare function getNonNegativeInteger(value: number): string;
|
|
15
19
|
export {};
|
|
16
20
|
//# sourceMappingURL=valueNodes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"valueNodes.d.ts","sourceRoot":"","sources":["../../../src/utils/valueNodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EACzB,SAAS,EACV,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAI9C,KAAK,mBAAmB,GAAG,yBAAyB,GAAG,SAAS,CAAC;AAEjE;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,mBAAmB,EAC1B,QAAQ,CAAC,EAAE,MAAM,GAChB,QAAQ,
|
|
1
|
+
{"version":3,"file":"valueNodes.d.ts","sourceRoot":"","sources":["../../../src/utils/valueNodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EACzB,SAAS,EACV,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAI9C,KAAK,mBAAmB,GAAG,yBAAyB,GAAG,SAAS,CAAC;AAEjE;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,mBAAmB,EAC1B,QAAQ,CAAC,EAAE,MAAM,GAChB,QAAQ,CAmDV;AAED,kFAAkF;AAClF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAWxE;AAED,uEAAuE;AACvE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUzD;AAED,oFAAoF;AACpF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM3D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getRenderMapVisitor.d.ts","sourceRoot":"","sources":["../../../src/visitors/getRenderMapVisitor.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,KAAK,SAAS,EAIf,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,OAAO,EASb,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAe,MAAM,qBAAqB,CAAC;AAa5E;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,UAAU,GAAG,aAAa,GAAG,aAAa,GAAG,iBAAiB,GAAG,iBAAiB,GAAG,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"getRenderMapVisitor.d.ts","sourceRoot":"","sources":["../../../src/visitors/getRenderMapVisitor.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,KAAK,SAAS,EAIf,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,OAAO,EASb,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAe,MAAM,qBAAqB,CAAC;AAa5E;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,UAAU,GAAG,aAAa,GAAG,aAAa,GAAG,iBAAiB,GAAG,iBAAiB,GAAG,SAAS,CAAC,CA2K9H"}
|
|
@@ -15,5 +15,5 @@ export declare function getTypeManifestVisitor(input: {
|
|
|
15
15
|
linkables: LinkableDictionary;
|
|
16
16
|
stack: NodeStack;
|
|
17
17
|
nonScalarEnums?: CamelCaseString[];
|
|
18
|
-
}): Visitor<TypeManifest, "accountBumpValueNode" | "accountValueNode" | "argumentValueNode" | "conditionalValueNode" | "identityValueNode" | "payerValueNode" | "pdaValueNode" | "programIdValueNode" | "resolverValueNode" | "programLinkNode" | "arrayValueNode" | "booleanValueNode" | "bytesValueNode" | "constantValueNode" | "enumValueNode" | "mapValueNode" | "noneValueNode" | "numberValueNode" | "publicKeyValueNode" | "setValueNode" | "someValueNode" | "stringValueNode" | "structValueNode" | "tupleValueNode" | "amountTypeNode" | "arrayTypeNode" | "booleanTypeNode" | "bytesTypeNode" | "dateTimeTypeNode" | "enumTypeNode" | "fixedSizeTypeNode" | "hiddenPrefixTypeNode" | "hiddenSuffixTypeNode" | "mapTypeNode" | "numberTypeNode" | "optionTypeNode" | "postOffsetTypeNode" | "preOffsetTypeNode" | "publicKeyTypeNode" | "remainderOptionTypeNode" | "sentinelTypeNode" | "setTypeNode" | "sizePrefixTypeNode" | "solAmountTypeNode" | "stringTypeNode" | "structTypeNode" | "tupleTypeNode" | "zeroableOptionTypeNode" | "constantDiscriminatorNode" | "fieldDiscriminatorNode" | "sizeDiscriminatorNode" | "accountNode" | "constantNode" | "definedTypeNode" | "errorNode" | "eventNode" | "instructionAccountNode" | "instructionArgumentNode" | "instructionByteDeltaNode" | "instructionNode" | "instructionRemainingAccountsNode" | "
|
|
18
|
+
}): Visitor<TypeManifest, "accountBumpValueNode" | "accountFieldValueNode" | "accountValueNode" | "argumentValueNode" | "conditionalValueNode" | "identityValueNode" | "payerValueNode" | "pdaValueNode" | "programIdValueNode" | "resolverValueNode" | "programLinkNode" | "arrayValueNode" | "booleanValueNode" | "bytesValueNode" | "constantValueNode" | "enumValueNode" | "injectedValueNode" | "mapValueNode" | "noneValueNode" | "numberValueNode" | "publicKeyValueNode" | "setValueNode" | "someValueNode" | "stringValueNode" | "structValueNode" | "tupleValueNode" | "amountTypeNode" | "arrayTypeNode" | "booleanTypeNode" | "bytesTypeNode" | "dateTimeTypeNode" | "enumTypeNode" | "fixedSizeTypeNode" | "hiddenPrefixTypeNode" | "hiddenSuffixTypeNode" | "mapTypeNode" | "numberTypeNode" | "optionTypeNode" | "postOffsetTypeNode" | "preOffsetTypeNode" | "publicKeyTypeNode" | "remainderOptionTypeNode" | "sentinelTypeNode" | "setTypeNode" | "sizePrefixTypeNode" | "solAmountTypeNode" | "stringTypeNode" | "structTypeNode" | "tupleTypeNode" | "zeroableOptionTypeNode" | "structFieldDisplayNode" | "constantDiscriminatorNode" | "fieldDiscriminatorNode" | "sizeDiscriminatorNode" | "instructionAccountDisplayNode" | "instructionStatusNode" | "accountNode" | "constantNode" | "definedTypeNode" | "errorNode" | "eventNode" | "instructionAccountNode" | "instructionArgumentNode" | "instructionByteDeltaNode" | "instructionNode" | "instructionRemainingAccountsNode" | "pdaNode" | "pluginNode" | "programNode" | "providedNode" | "pdaSeedValueNode" | "fixedCountNode" | "prefixedCountNode" | "remainderCountNode" | "amountNumberDisplayNode" | "dateTimeNumberDisplayNode" | "durationNumberDisplayNode" | "enumVariantDisplayNode" | "instructionDisplayNode" | "stringDisplayNode" | "accountLinkNode" | "definedTypeLinkNode" | "instructionAccountLinkNode" | "instructionArgumentLinkNode" | "instructionLinkNode" | "pdaLinkNode" | "constantPdaSeedNode" | "variablePdaSeedNode" | "enumEmptyVariantTypeNode" | "enumStructVariantTypeNode" | "enumTupleVariantTypeNode" | "structFieldTypeNode" | "mapEntryValueNode" | "structFieldValueNode" | "rootNode">;
|
|
19
19
|
//# sourceMappingURL=getTypeManifestVisitor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getTypeManifestVisitor.d.ts","sourceRoot":"","sources":["../../../src/visitors/getTypeManifestVisitor.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,eAAe,
|
|
1
|
+
{"version":3,"file":"getTypeManifestVisitor.d.ts","sourceRoot":"","sources":["../../../src/visitors/getTypeManifestVisitor.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,eAAe,EAgCrB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,SAAS,EACd,KAAK,OAAO,EAIb,MAAM,uBAAuB,CAAC;AAI/B,OAAO,EAEL,KAAK,YAAY,EAKlB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,KAAK,WAAW,EAAa,MAAM,8BAA8B,CAAC;AAG3E;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAE5E;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE;IAC5C,OAAO,EAAE,WAAW,CAAC;IACrB,SAAS,EAAE,kBAAkB,CAAC;IAC9B,KAAK,EAAE,SAAS,CAAC;IACjB,cAAc,CAAC,EAAE,eAAe,EAAE,CAAC;CACpC,8kEA8mBA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderVisitor.d.ts","sourceRoot":"","sources":["../../../src/visitors/renderVisitor.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAMzD;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,aAAkB,
|
|
1
|
+
{"version":3,"file":"renderVisitor.d.ts","sourceRoot":"","sources":["../../../src/visitors/renderVisitor.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAMzD;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,aAAkB,6DAmE5B"}
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dependencies": {
|
|
3
|
-
"@codama/errors": "^1.10.
|
|
4
|
-
"@codama/nodes": "^1.10.
|
|
5
|
-
"@codama/renderers-core": "^1.
|
|
6
|
-
"@codama/visitors-core": "^1.10.
|
|
3
|
+
"@codama/errors": "^1.10.2",
|
|
4
|
+
"@codama/nodes": "^1.10.2",
|
|
5
|
+
"@codama/renderers-core": "^1.4.0",
|
|
6
|
+
"@codama/visitors-core": "^1.10.2"
|
|
7
7
|
},
|
|
8
8
|
"description": "Codama renderer for generating Dart code targeting the solana_kit SDK",
|
|
9
9
|
"devDependencies": {
|
|
10
|
-
"@codama/nodes-from-anchor": "^1.5.
|
|
11
|
-
"@codama/renderers-js": "^2.
|
|
10
|
+
"@codama/nodes-from-anchor": "^1.5.5",
|
|
11
|
+
"@codama/renderers-js": "^2.4.0",
|
|
12
12
|
"@types/node": "25.3.0",
|
|
13
13
|
"@vitest/coverage-v8": "4.1.0",
|
|
14
14
|
"rimraf": "6.1.3",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"repository": "https://github.com/openbudgetfun/solana_kit/tree/main/packages/codama-renderers-dart",
|
|
56
56
|
"type": "module",
|
|
57
57
|
"types": "./dist/types/index.d.ts",
|
|
58
|
-
"version": "0.5.
|
|
58
|
+
"version": "0.5.4",
|
|
59
59
|
"scripts": {
|
|
60
60
|
"build": "pnpm exec rimraf dist && pnpm exec tsup && pnpm exec tsc -p tsconfig.declarations.json",
|
|
61
61
|
"lint": "eslint --ext .ts src",
|
|
@@ -16,6 +16,7 @@ import { getDiscriminatorValidationFragment } from "../utils/discriminators.js";
|
|
|
16
16
|
import { getTopLevelDecoderFragment } from "../utils/exactDecoder.js";
|
|
17
17
|
import {
|
|
18
18
|
getDartValueFragment,
|
|
19
|
+
getNonNegativeInteger,
|
|
19
20
|
isConstDartValueNode,
|
|
20
21
|
} from "../utils/valueNodes.js";
|
|
21
22
|
import { getDiscriminatorConstantsFragment } from "./discriminatorConstants.js";
|
|
@@ -160,7 +161,7 @@ export function getAccountPageFragment(
|
|
|
160
161
|
const sizeFragment = node.size != null
|
|
161
162
|
? fragment`
|
|
162
163
|
/// The size of the [${fragmentFromString(typeName)}] account data in bytes.
|
|
163
|
-
const int ${fragmentFromString(scope.nameApi.accountSizeConstant(name))} = ${fragmentFromString(
|
|
164
|
+
const int ${fragmentFromString(scope.nameApi.accountSizeConstant(name))} = ${fragmentFromString(getNonNegativeInteger(node.size))};`
|
|
164
165
|
: emptyFragment();
|
|
165
166
|
|
|
166
167
|
// Discriminator
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
mergeFragments,
|
|
9
9
|
use,
|
|
10
10
|
} from "../utils/fragment.js";
|
|
11
|
+
import { getNonNegativeInteger, toDartStringLiteral } from "../utils/valueNodes.js";
|
|
11
12
|
import type { RenderScope } from "../utils/options.js";
|
|
12
13
|
import { camelCase, pascalCase, screamingSnakeCase } from "../utils/nameTransformers.js";
|
|
13
14
|
|
|
@@ -30,11 +31,12 @@ export function getErrorPageFragment(
|
|
|
30
31
|
programName,
|
|
31
32
|
err.name as string,
|
|
32
33
|
);
|
|
34
|
+
getNonNegativeInteger(err.code);
|
|
33
35
|
const hexCode = `0x${err.code.toString(16)}`;
|
|
34
36
|
const docs = err.docs?.length
|
|
35
|
-
? err.docs.map(
|
|
37
|
+
? err.docs.map(toDartDocComment).join("\n") + "\n"
|
|
36
38
|
: "";
|
|
37
|
-
const message = err.message ?
|
|
39
|
+
const message = err.message ? `${toDartDocComment(`Message: "${err.message}"`)}\n` : "";
|
|
38
40
|
return `${docs}${message}const int ${constName} = ${hexCode}; // ${err.code}`;
|
|
39
41
|
})
|
|
40
42
|
.join("\n\n");
|
|
@@ -47,7 +49,7 @@ export function getErrorPageFragment(
|
|
|
47
49
|
err.name as string,
|
|
48
50
|
);
|
|
49
51
|
const message = err.message ?? err.name as string;
|
|
50
|
-
return ` ${constName}:
|
|
52
|
+
return ` ${constName}: ${toDartStringLiteral(message)},`;
|
|
51
53
|
})
|
|
52
54
|
.join("\n");
|
|
53
55
|
|
|
@@ -77,6 +79,7 @@ bool ${fragmentFromString(isErrorFnName)}(int code) {
|
|
|
77
79
|
}`;
|
|
78
80
|
}
|
|
79
81
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
/** Prefix every physical line so IDL documentation cannot become Dart code. */
|
|
83
|
+
function toDartDocComment(value: string): string {
|
|
84
|
+
return value.split(/\r\n?|\n/).map((line) => `/// ${line}`).join("\n");
|
|
82
85
|
}
|
|
@@ -172,11 +172,35 @@ export function getInstructionPageFragment(
|
|
|
172
172
|
const dataDecoderName = `get${typeName}InstructionDataDecoder`;
|
|
173
173
|
const dataCodecName = `get${typeName}InstructionDataCodec`;
|
|
174
174
|
|
|
175
|
-
//
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
175
|
+
// Generated parameters and locals must not shadow IDL account or argument names.
|
|
176
|
+
const usedNames = new Set([
|
|
177
|
+
...args.map((arg) => camelCase(arg.name as string)),
|
|
178
|
+
...accounts.map((account) => camelCase(account.name as string)),
|
|
179
|
+
]);
|
|
180
|
+
const instrProgramParam = reserveName(
|
|
181
|
+
usedNames.has("programAddress") ? "instructionProgramAddress" : "programAddress",
|
|
182
|
+
usedNames,
|
|
183
|
+
);
|
|
184
|
+
const instructionDataLocal = reserveName("instructionData", usedNames);
|
|
185
|
+
const signerParams = new Map<InstructionAccountNode, string>();
|
|
186
|
+
|
|
187
|
+
for (const account of accounts) {
|
|
188
|
+
if (account.isSigner === "either") {
|
|
189
|
+
signerParams.set(
|
|
190
|
+
account,
|
|
191
|
+
reserveName(`${camelCase(account.name as string)}IsSigner`, usedNames),
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const signerParamDeclarations = [...signerParams.values()]
|
|
197
|
+
.map((parameter) => ` bool ${parameter} = true,`)
|
|
198
|
+
.join("\n");
|
|
199
|
+
const signerParamDocs = [...signerParams.entries()]
|
|
200
|
+
.map(([account, parameter]) =>
|
|
201
|
+
`/// Set [${parameter}] to false when [${camelCase(account.name as string)}] does not sign (for example, a multisig authority).`
|
|
202
|
+
)
|
|
203
|
+
.join("\n");
|
|
180
204
|
|
|
181
205
|
// Build the instruction builder function
|
|
182
206
|
const accountParams = accounts
|
|
@@ -214,7 +238,7 @@ export function getInstructionPageFragment(
|
|
|
214
238
|
const accountMetas = accounts
|
|
215
239
|
.map((acc) => {
|
|
216
240
|
const fieldName = camelCase(acc.name as string);
|
|
217
|
-
const role = getAccountRole(acc);
|
|
241
|
+
const role = getAccountRole(acc, signerParams.get(acc));
|
|
218
242
|
const isOptional = acc.isOptional ?? false;
|
|
219
243
|
if (isOptional) {
|
|
220
244
|
if (optionalAccountStrategy === "omitted") {
|
|
@@ -316,13 +340,13 @@ Codec<${fragmentFromString(dataClassName)}, ${fragmentFromString(dataClassName)}
|
|
|
316
340
|
|
|
317
341
|
// Instruction builder
|
|
318
342
|
parts.push(fragment`
|
|
319
|
-
/// Creates a [${fragmentFromString(typeName)}] instruction
|
|
343
|
+
/// Creates a [${fragmentFromString(typeName)}] instruction.${fragmentFromString(signerParamDocs ? `\n${signerParamDocs}` : "")}
|
|
320
344
|
Instruction ${fragmentFromString(instrFnName)}({
|
|
321
345
|
required Address ${fragmentFromString(instrProgramParam)},
|
|
322
346
|
${fragmentFromString(accountParams)}
|
|
323
|
-
${fragmentFromString(argParams)}
|
|
347
|
+
${fragmentFromString(argParams)}${fragmentFromString(signerParamDeclarations ? `\n${signerParamDeclarations}` : "")}
|
|
324
348
|
}) {
|
|
325
|
-
final
|
|
349
|
+
final ${instructionDataLocal} = ${fragmentFromString(dataClassName)}(
|
|
326
350
|
${fragmentFromString(dataConstruction)}
|
|
327
351
|
);
|
|
328
352
|
|
|
@@ -331,7 +355,7 @@ ${fragmentFromString(dataConstruction)}
|
|
|
331
355
|
accounts: [
|
|
332
356
|
${fragmentFromString(accountMetas)}
|
|
333
357
|
],
|
|
334
|
-
data: ${fragmentFromString(dataEncoderName)}().encode(
|
|
358
|
+
data: ${fragmentFromString(dataEncoderName)}().encode(${instructionDataLocal}),
|
|
335
359
|
);
|
|
336
360
|
}`);
|
|
337
361
|
|
|
@@ -357,14 +381,27 @@ ${fragmentFromString(dataClassName)} ${fragmentFromString(parseFnName)}(Instruct
|
|
|
357
381
|
return result;
|
|
358
382
|
}
|
|
359
383
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
384
|
+
/** Reserves an identifier without shadowing existing builder parameters or locals. */
|
|
385
|
+
function reserveName(preferredName: string, usedNames: Set<string>): string {
|
|
386
|
+
let name = preferredName;
|
|
387
|
+
|
|
388
|
+
while (usedNames.has(name)) {
|
|
389
|
+
name = `${name}_`;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
usedNames.add(name);
|
|
393
|
+
return name;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/** Preserves fixed permissions and lets either-signer accounts choose their role. */
|
|
397
|
+
function getAccountRole(acc: InstructionAccountNode, signerParameter?: string): string {
|
|
398
|
+
const role = acc.isWritable ? "AccountRole.writable" : "AccountRole.readonly";
|
|
399
|
+
|
|
400
|
+
if (signerParameter) {
|
|
401
|
+
return `${signerParameter} ? ${role}Signer : ${role}`;
|
|
402
|
+
}
|
|
363
403
|
|
|
364
|
-
|
|
365
|
-
if (isSigner) return "AccountRole.readonlySigner";
|
|
366
|
-
if (isWritable) return "AccountRole.writable";
|
|
367
|
-
return "AccountRole.readonly";
|
|
404
|
+
return acc.isSigner === true ? `${role}Signer` : role;
|
|
368
405
|
}
|
|
369
406
|
|
|
370
407
|
function isDiscriminatorArg(
|
package/src/fragments/pdaPage.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from "../utils/fragment.js";
|
|
11
11
|
import type { RenderScope } from "../utils/options.js";
|
|
12
12
|
import { camelCase, pascalCase } from "../utils/nameTransformers.js";
|
|
13
|
+
import { getDartValueFragment, toDartStringLiteral } from "../utils/valueNodes.js";
|
|
13
14
|
import type { TypeManifest } from "../utils/typeManifest.js";
|
|
14
15
|
import { WELL_KNOWN_ADDRESSES } from "../utils/wellKnownAddresses.js";
|
|
15
16
|
|
|
@@ -66,9 +67,9 @@ export function getPdaPageFragment(
|
|
|
66
67
|
for (const seed of seeds) {
|
|
67
68
|
if (seed.kind === "constantPdaSeedNode") {
|
|
68
69
|
if (seed.value.kind === "bytesValueNode") {
|
|
69
|
-
seedValues.push(`
|
|
70
|
+
seedValues.push(` ${getDartValueFragment(seed.value).content},`);
|
|
70
71
|
} else if (seed.value.kind === "stringValueNode") {
|
|
71
|
-
seedValues.push(`
|
|
72
|
+
seedValues.push(` ${toDartStringLiteral(seed.value.string)},`);
|
|
72
73
|
} else if (seed.value.kind === "publicKeyValueNode") {
|
|
73
74
|
const wellKnownSeedName = WELL_KNOWN_ADDRESSES.get(seed.value.publicKey);
|
|
74
75
|
if (wellKnownSeedName) {
|
|
@@ -78,13 +79,14 @@ export function getPdaPageFragment(
|
|
|
78
79
|
);
|
|
79
80
|
} else {
|
|
80
81
|
seedValues.push(
|
|
81
|
-
` getAddressEncoder().encode(Address(
|
|
82
|
+
` getAddressEncoder().encode(Address(${toDartStringLiteral(seed.value.publicKey)})),`,
|
|
82
83
|
);
|
|
83
84
|
}
|
|
84
85
|
} else if (seed.value.kind === "numberValueNode") {
|
|
85
86
|
const manifest = visit(seed.type, scope.typeManifestVisitor);
|
|
86
87
|
seedManifests.push(manifest);
|
|
87
|
-
|
|
88
|
+
const value = getDartValueFragment(seed.value, manifest.type.content);
|
|
89
|
+
seedValues.push(` ${manifest.encoder.content}.encode(${value.content}),`);
|
|
88
90
|
}
|
|
89
91
|
} else if (seed.kind === "variablePdaSeedNode") {
|
|
90
92
|
const manifest = visit(seed.type, scope.typeManifestVisitor);
|
|
@@ -105,7 +107,7 @@ export function getPdaPageFragment(
|
|
|
105
107
|
const programIdParam = node.programId
|
|
106
108
|
? wellKnownProgramName
|
|
107
109
|
? `Address programAddress = ${wellKnownProgramName}`
|
|
108
|
-
: `Address programAddress = const Address(
|
|
110
|
+
: `Address programAddress = const Address(${toDartStringLiteral(node.programId)})`
|
|
109
111
|
: "required Address programAddress";
|
|
110
112
|
|
|
111
113
|
const typedDataImport = hasByteSeeds
|
|
@@ -167,12 +169,3 @@ ${fragmentFromString(seedValues.join("\n"))}
|
|
|
167
169
|
|
|
168
170
|
return result;
|
|
169
171
|
}
|
|
170
|
-
|
|
171
|
-
function bytesValueToDart(hex: string): string {
|
|
172
|
-
const clean = hex.replace(/^0x/, "");
|
|
173
|
-
const pairs: string[] = [];
|
|
174
|
-
for (let i = 0; i < clean.length; i += 2) {
|
|
175
|
-
pairs.push(`0x${clean.slice(i, i + 2)}`);
|
|
176
|
-
}
|
|
177
|
-
return `[${pairs.join(", ")}]`;
|
|
178
|
-
}
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from "../utils/fragment.js";
|
|
17
17
|
import type { RenderScope } from "../utils/options.js";
|
|
18
18
|
import { camelCase, pascalCase } from "../utils/nameTransformers.js";
|
|
19
|
+
import { toDartStringLiteral } from "../utils/valueNodes.js";
|
|
19
20
|
import { WELL_KNOWN_ADDRESSES } from "../utils/wellKnownAddresses.js";
|
|
20
21
|
|
|
21
22
|
/**
|
|
@@ -55,7 +56,7 @@ const ${fragmentFromString(addressConstName)} = ${fragmentFromString(wellKnownNa
|
|
|
55
56
|
${use("Address", "solanaAddresses")}
|
|
56
57
|
|
|
57
58
|
/// The address of the ${fragmentFromString(pascalCase(name))} program.
|
|
58
|
-
const ${fragmentFromString(addressConstName)} = Address(
|
|
59
|
+
const ${fragmentFromString(addressConstName)} = Address(${fragmentFromString(toDartStringLiteral(node.publicKey))});`;
|
|
59
60
|
|
|
60
61
|
const parts: Fragment[] = [addressDeclaration];
|
|
61
62
|
|
|
@@ -232,7 +233,7 @@ function getValueFragment(
|
|
|
232
233
|
case "booleanValueNode":
|
|
233
234
|
return fragmentFromString(String(value.boolean));
|
|
234
235
|
case "stringValueNode":
|
|
235
|
-
return fragmentFromString(
|
|
236
|
+
return fragmentFromString(toDartStringLiteral(value.string));
|
|
236
237
|
case "bytesValueNode": {
|
|
237
238
|
const clean = value.data.replace(/^0x/, "");
|
|
238
239
|
const bytes = clean.match(/.{1,2}/g)?.map((byte) => parseInt(byte, 16)) ?? [];
|
|
@@ -147,6 +147,7 @@ function getDataEnumPageFragment(
|
|
|
147
147
|
const decoderVariants: string[] = [];
|
|
148
148
|
const encodeCases: string[] = [];
|
|
149
149
|
const decodeCases: string[] = [];
|
|
150
|
+
let pageHasListEnums = false;
|
|
150
151
|
// Collect all field type manifests from variants so we can merge their imports
|
|
151
152
|
const allVariantManifests: { encoder: Fragment; decoder: Fragment; type: Fragment }[] = [];
|
|
152
153
|
|
|
@@ -212,12 +213,18 @@ function getDataEnumPageFragment(
|
|
|
212
213
|
fields.length === 0
|
|
213
214
|
? "true"
|
|
214
215
|
: fields
|
|
215
|
-
.map((f: StructFieldTypeNode) =>
|
|
216
|
+
.map((f: StructFieldTypeNode, index) => {
|
|
217
|
+
const fieldName = camelCase(f.name as string);
|
|
218
|
+
return isListManifest(fieldManifests[index].manifest)
|
|
219
|
+
? `_listEquals(${fieldName}, other.${fieldName})`
|
|
220
|
+
: `${fieldName} == other.${fieldName}`;
|
|
221
|
+
})
|
|
216
222
|
.join(" &&\n ");
|
|
217
223
|
|
|
218
|
-
const hashExpression =
|
|
219
|
-
|
|
220
|
-
|
|
224
|
+
const hashExpression = getValueHashExpression(fields, fieldManifests);
|
|
225
|
+
if (fieldManifests.some(({ manifest }) => isListManifest(manifest))) {
|
|
226
|
+
pageHasListEnums = true;
|
|
227
|
+
}
|
|
221
228
|
|
|
222
229
|
const toStringFields = fields
|
|
223
230
|
.map((f: StructFieldTypeNode) => `${camelCase(f.name as string)}: $${camelCase(f.name as string)}`)
|
|
@@ -351,7 +358,7 @@ sealed class ${fragmentFromString(typeName)} {
|
|
|
351
358
|
const ${fragmentFromString(typeName)}();
|
|
352
359
|
}
|
|
353
360
|
|
|
354
|
-
${fragmentFromString(variantClasses.join("\n\n"))}
|
|
361
|
+
${fragmentFromString(variantClasses.join("\n\n"))}${pageHasListEnums ? LIST_VALUE_HELPERS : ""}
|
|
355
362
|
|
|
356
363
|
Encoder<${fragmentFromString(typeName)}> ${fragmentFromString(encoderName)}() {
|
|
357
364
|
return transformEncoder<Map<String, Object?>, ${fragmentFromString(typeName)}>(
|
|
@@ -405,6 +412,7 @@ function getStructPageFragment(
|
|
|
405
412
|
if (structNode.kind !== "structTypeNode") return emptyFragment();
|
|
406
413
|
|
|
407
414
|
const fields = structNode.fields ?? [];
|
|
415
|
+
let pageHasListStructs = false;
|
|
408
416
|
|
|
409
417
|
// Visit each field type once and collect manifests for reuse
|
|
410
418
|
const fieldManifests = fields.map((f: StructFieldTypeNode) => ({
|
|
@@ -429,19 +437,17 @@ function getStructPageFragment(
|
|
|
429
437
|
const eqChecks =
|
|
430
438
|
fields.length === 0
|
|
431
439
|
? "true"
|
|
432
|
-
:
|
|
433
|
-
.map(
|
|
434
|
-
(f
|
|
435
|
-
|
|
436
|
-
|
|
440
|
+
: fieldManifests
|
|
441
|
+
.map(({ field: f, manifest }, index) => {
|
|
442
|
+
const fieldName = camelCase(f.name as string);
|
|
443
|
+
return isListManifest(manifest)
|
|
444
|
+
? `_listEquals(${fieldName}, other.${fieldName})`
|
|
445
|
+
: `${fieldName} == other.${fieldName}`;
|
|
446
|
+
})
|
|
437
447
|
.join(" &&\n ");
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
? "runtimeType"
|
|
442
|
-
: fields
|
|
443
|
-
.map((f: StructFieldTypeNode) => camelCase(f.name as string))
|
|
444
|
-
.join(", ");
|
|
448
|
+
if (fieldManifests.some(({ manifest }) => isListManifest(manifest))) {
|
|
449
|
+
pageHasListStructs = true;
|
|
450
|
+
}
|
|
445
451
|
|
|
446
452
|
const toStringFields = fields
|
|
447
453
|
.map(
|
|
@@ -511,12 +517,14 @@ ${fragmentFromString(fieldDecls)}
|
|
|
511
517
|
${fragmentFromString(eqChecks)};
|
|
512
518
|
|
|
513
519
|
@override
|
|
514
|
-
int get hashCode => ${fragmentFromString(
|
|
520
|
+
int get hashCode => ${fragmentFromString(
|
|
521
|
+
getValueHashExpression(fields, fieldManifests),
|
|
522
|
+
)};
|
|
515
523
|
|
|
516
524
|
@override
|
|
517
525
|
String toString() => '${fragmentFromString(typeName)}(${fragmentFromString(toStringFields)})';
|
|
518
526
|
}
|
|
519
|
-
|
|
527
|
+
${pageHasListStructs ? LIST_VALUE_HELPERS : ""}
|
|
520
528
|
Encoder<${fragmentFromString(typeName)}> ${fragmentFromString(encoderName)}() {
|
|
521
529
|
final structEncoder = getStructEncoder(<(String, Encoder<Object?>)>[
|
|
522
530
|
${fragmentFromString(encFields)}
|
|
@@ -595,6 +603,81 @@ Codec<${fragmentFromString(typeName)}, ${fragmentFromString(typeName)}> ${fragme
|
|
|
595
603
|
}`;
|
|
596
604
|
}
|
|
597
605
|
|
|
606
|
+
/**
|
|
607
|
+
* Returns true when the rendered field type is a Dart list or byte sequence,
|
|
608
|
+
* whose reference equality must be replaced with a deep comparison in
|
|
609
|
+
* generated value classes.
|
|
610
|
+
*/
|
|
611
|
+
function isListManifest(manifest: { type: Fragment }): boolean {
|
|
612
|
+
return manifest.type.content.startsWith("List<") ||
|
|
613
|
+
manifest.type.content === "Uint8List";
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* Private Dart helpers emitted into pages whose value classes contain
|
|
618
|
+
* list-typed fields, so `==` and `hashCode` match recursive structural value
|
|
619
|
+
* equality instead of list reference identity. The recursive branch matters
|
|
620
|
+
* for generated types such as `List<Uint8List>`.
|
|
621
|
+
*/
|
|
622
|
+
const LIST_VALUE_HELPERS = `
|
|
623
|
+
bool _listEquals<T>(List<T>? a, List<T>? b) {
|
|
624
|
+
if (identical(a, b)) return true;
|
|
625
|
+
if (a == null || b == null) return a == b;
|
|
626
|
+
if (a.length != b.length) return false;
|
|
627
|
+
for (var i = 0; i < a.length; i++) {
|
|
628
|
+
final left = a[i];
|
|
629
|
+
final right = b[i];
|
|
630
|
+
if (left is List<Object?> && right is List<Object?>) {
|
|
631
|
+
if (!_listEquals(left, right)) return false;
|
|
632
|
+
} else if (left != right) {
|
|
633
|
+
return false;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
return true;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
Object? _deepHash(Object? value) {
|
|
640
|
+
if (value is List<Object?>) {
|
|
641
|
+
return Object.hashAll(value.map(_deepHash));
|
|
642
|
+
}
|
|
643
|
+
return value;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
int _listHashCode<T>(List<T>? a) {
|
|
647
|
+
if (a == null) return 0;
|
|
648
|
+
return Object.hashAll(a.map(_deepHash));
|
|
649
|
+
}
|
|
650
|
+
`;
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Builds the `hashCode` expression for a class whose fields render as the
|
|
654
|
+
* given lowercase names. List-typed fields compare structurally through the
|
|
655
|
+
* private `_listHashCode` helper emitted alongside the class.
|
|
656
|
+
*/
|
|
657
|
+
function getValueHashExpression(
|
|
658
|
+
fields: StructFieldTypeNode[],
|
|
659
|
+
fieldManifests: { field: StructFieldTypeNode; manifest: { type: Fragment } }[],
|
|
660
|
+
): string {
|
|
661
|
+
const fieldNames = fields.map((f: StructFieldTypeNode) =>
|
|
662
|
+
camelCase(f.name as string),
|
|
663
|
+
);
|
|
664
|
+
const hasListFields = fieldManifests.some(({ manifest }) =>
|
|
665
|
+
isListManifest(manifest),
|
|
666
|
+
);
|
|
667
|
+
if (!hasListFields) {
|
|
668
|
+
return getHashExpression(fieldNames);
|
|
669
|
+
}
|
|
670
|
+
if (fieldNames.length === 1) {
|
|
671
|
+
return `_listHashCode(${fieldNames[0]})`;
|
|
672
|
+
}
|
|
673
|
+
const hashArgs = fields.map((f: StructFieldTypeNode, index) =>
|
|
674
|
+
isListManifest(fieldManifests[index].manifest)
|
|
675
|
+
? `_listHashCode(${camelCase(f.name as string)})`
|
|
676
|
+
: camelCase(f.name as string),
|
|
677
|
+
);
|
|
678
|
+
return `Object.hash(${hashArgs.join(", ")})`;
|
|
679
|
+
}
|
|
680
|
+
|
|
598
681
|
function getHashExpression(fields: string[]): string {
|
|
599
682
|
if (fields.length === 0) return "runtimeType.hashCode";
|
|
600
683
|
if (fields.length === 1) return `${fields[0]}.hashCode`;
|
package/src/utils/formatCode.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { execSync } from "node:child_process";
|
|
1
|
+
import { execFileSync, execSync } from "node:child_process";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Format Dart code using `dart format`.
|
|
@@ -23,7 +23,7 @@ export function formatDartCode(code: string): string {
|
|
|
23
23
|
* Format all Dart files in a directory using `dart format`.
|
|
24
24
|
*/
|
|
25
25
|
export function formatDartDirectory(dir: string): void {
|
|
26
|
-
|
|
26
|
+
execFileSync("dart", ["format", "--", dir], {
|
|
27
27
|
encoding: "utf-8",
|
|
28
28
|
timeout: 60_000,
|
|
29
29
|
stdio: ["pipe", "pipe", "pipe"],
|