Эх сурвалжийг харах

Add ZeroableOption to TypeManifest visitor

Loris Leiva 1 жил өмнө
parent
commit
da4c07029b

+ 31 - 0
packages/renderers-js/src/getTypeManifestVisitor.ts

@@ -815,6 +815,37 @@ export function getTypeManifestVisitor(input: {
                         { mergeValues: renders => `[${renders.join(', ')}]` },
                     );
                 },
+
+                visitZeroableOptionType(node, { self }) {
+                    const childManifest = visit(node.item, self);
+                    childManifest.strictType.mapRender(r => `Option<${r}>`).addImports('solanaOptions', 'Option');
+                    childManifest.looseType
+                        .mapRender(r => `OptionOrNullable<${r}>`)
+                        .addImports('solanaOptions', 'OptionOrNullable');
+                    const encoderOptions: string[] = [];
+                    const decoderOptions: string[] = [];
+
+                    // Zero-value option.
+                    if (node.zeroValue) {
+                        const zeroValueManifest = visit(node.zeroValue, self);
+                        childManifest.encoder.mergeImportsWith(zeroValueManifest.value);
+                        childManifest.decoder.mergeImportsWith(zeroValueManifest.value);
+                        encoderOptions.push(`zeroValue: ${zeroValueManifest.value.render}`);
+                        decoderOptions.push(`zeroValue: ${zeroValueManifest.value.render}`);
+                    }
+
+                    const encoderOptionsAsString =
+                        encoderOptions.length > 0 ? `, { ${encoderOptions.join(', ')} }` : '';
+                    const decoderOptionsAsString =
+                        decoderOptions.length > 0 ? `, { ${decoderOptions.join(', ')} }` : '';
+                    childManifest.encoder
+                        .mapRender(r => `getZeroableOptionEncoder(${r + encoderOptionsAsString})`)
+                        .addImports('solanaOptions', 'getZeroableOptionEncoder');
+                    childManifest.decoder
+                        .mapRender(r => `getZeroableOptionDecoder(${r + decoderOptionsAsString})`)
+                        .addImports('solanaOptions', 'getZeroableOptionDecoder');
+                    return childManifest;
+                },
             }),
     );
 }

+ 74 - 0
packages/renderers-js/test/types/zeroableOption.test.ts

@@ -0,0 +1,74 @@
+import {
+    constantValueNodeFromBytes,
+    definedTypeNode,
+    numberTypeNode,
+    publicKeyTypeNode,
+    zeroableOptionTypeNode,
+} from '@kinobi-so/nodes';
+import { visit } from '@kinobi-so/visitors-core';
+import test from 'ava';
+
+import { getRenderMapVisitor } from '../../src/index.js';
+import { renderMapContains, renderMapContainsImports } from '../_setup.js';
+
+test('it renders zeroable option codecs', t => {
+    // Given the following node.
+    const node = definedTypeNode({
+        name: 'myType',
+        type: zeroableOptionTypeNode(publicKeyTypeNode()),
+    });
+
+    // When we render it.
+    const renderMap = visit(node, getRenderMapVisitor());
+
+    // Then we expect the following types and codecs to be exported.
+    renderMapContains(t, renderMap, 'types/myType.ts', [
+        'export type MyType = Option<Address>',
+        'export type MyTypeArgs = OptionOrNullable<Address>',
+        'getZeroableOptionEncoder( getAddressEncoder() )',
+        'getZeroableOptionDecoder( getAddressDecoder() )',
+    ]);
+
+    // And we expect the following codec imports.
+    renderMapContainsImports(t, renderMap, 'types/myType.ts', {
+        '@solana/web3.js': [
+            'getZeroableOptionEncoder',
+            'getZeroableOptionDecoder',
+            'getAddressEncoder',
+            'getAddressDecoder',
+            'Option',
+            'OptionOrNullable',
+        ],
+    });
+});
+
+test('it renders zeroable option codecs with custom zero values', t => {
+    // Given the following node.
+    const node = definedTypeNode({
+        name: 'myType',
+        type: zeroableOptionTypeNode(numberTypeNode('u16'), constantValueNodeFromBytes('base16', 'ffff')),
+    });
+
+    // When we render it.
+    const renderMap = visit(node, getRenderMapVisitor());
+
+    // Then we expect the following types and codecs to be exported.
+    renderMapContains(t, renderMap, 'types/myType.ts', [
+        'export type MyType = Option<number>',
+        'export type MyTypeArgs = OptionOrNullable<number>',
+        'getZeroableOptionEncoder( getU16Encoder(), { zeroValue: new Uint8Array([255, 255]) } )',
+        'getZeroableOptionDecoder( getU16Decoder(), { zeroValue: new Uint8Array([255, 255]) } )',
+    ]);
+
+    // And we expect the following codec imports.
+    renderMapContainsImports(t, renderMap, 'types/myType.ts', {
+        '@solana/web3.js': [
+            'getZeroableOptionEncoder',
+            'getZeroableOptionDecoder',
+            'getU16Encoder',
+            'getU16Decoder',
+            'Option',
+            'OptionOrNullable',
+        ],
+    });
+});