Skip to content

Commit

Permalink
Update enums codecs from latest Web3.js version
Browse files Browse the repository at this point in the history
This PR updates the JS experimental renderer to use the latest version of the new Web3.js and adjusts the Data Enum and Scalar Enum codecs, now known as Discriminated Union and Enum codecs respectively.
  • Loading branch information
lorisleiva committed Mar 27, 2024
1 parent bc6e82c commit 0434144
Show file tree
Hide file tree
Showing 31 changed files with 249 additions and 200 deletions.
5 changes: 5 additions & 0 deletions .changeset/poor-lions-promise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@metaplex-foundation/kinobi": minor
---

Update enums codecs from latest Web3.js version on the JS experimental renderer
2 changes: 1 addition & 1 deletion src/renderers/js-experimental/fragments/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export * from './programErrors';
export * from './programInstructions';
export * from './type';
export * from './typeCodec';
export * from './typeDataEnumHelpers';
export * from './typeDecoder';
export * from './typeDiscriminatedUnionHelpers';
export * from './typeEncoder';
export * from './typeWithCodec';
23 changes: 0 additions & 23 deletions src/renderers/js-experimental/fragments/typeDataEnumHelpers.njk

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Data Enum Helpers.
{% for variant in typeNode.variants %}
{% if variant.kind === 'enumStructVariantTypeNode' %}
export function {{ discriminatedUnionFunction }}(kind: '{{ getVariant(variant.name) }}', data: GetDiscriminatedUnionVariantContent<{{ looseName }}, '__kind', '{{ getVariant(variant.name) }}'>): GetDiscriminatedUnionVariant<{{ looseName }}, '__kind', '{{ getVariant(variant.name) }}'>;
{% elif variant.kind === 'enumTupleVariantTypeNode' %}
export function {{ discriminatedUnionFunction }}(kind: '{{ getVariant(variant.name) }}', data: GetDiscriminatedUnionVariantContent<{{ looseName }}, '__kind', '{{ getVariant(variant.name) }}'>['fields']): GetDiscriminatedUnionVariant<{{ looseName }}, '__kind', '{{ getVariant(variant.name) }}'>;
{% else %}
export function {{ discriminatedUnionFunction }}(kind: '{{ getVariant(variant.name) }}'): GetDiscriminatedUnionVariant<{{ looseName }}, '__kind', '{{ getVariant(variant.name) }}'>;
{% endif %}
{% endfor %}
export function {{ discriminatedUnionFunction }}<K extends {{ looseName }}['{{ discriminatedUnionDiscriminator }}'], Data>(
kind: K,
data?: Data,
) {
return Array.isArray(data) ? { {{ discriminatedUnionDiscriminator }}: kind, fields: data } : { {{ discriminatedUnionDiscriminator }}: kind, ...(data ?? {}) };
}

export function {{ isDiscriminatedUnionFunction }}<K extends {{ strictName }}['{{ discriminatedUnionDiscriminator }}']>(
kind: K,
value: {{ strictName }},
): value is {{ strictName }} & { {{ discriminatedUnionDiscriminator }}: K } {
return value.{{ discriminatedUnionDiscriminator }} === kind;
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,31 @@ import { TypeNode, isDataEnum, isNode } from '../../../nodes';
import type { GlobalFragmentScope } from '../getRenderMapVisitor';
import { Fragment, fragment, fragmentFromTemplate } from './common';

export function getTypeDataEnumHelpersFragment(
export function getTypeDiscriminatedUnionHelpersFragment(
scope: Pick<GlobalFragmentScope, 'nameApi'> & {
name: string;
typeNode: TypeNode;
}
): Fragment {
const { name, typeNode, nameApi } = scope;
const isDataEnumNode =
const isDiscriminatedUnion =
isNode(typeNode, 'enumTypeNode') && isDataEnum(typeNode);

if (!isDataEnumNode) {
if (!isDiscriminatedUnion) {
return fragment('');
}

return fragmentFromTemplate('typeDataEnumHelpers.njk', {
return fragmentFromTemplate('typeDiscriminatedUnionHelpers.njk', {
strictName: nameApi.dataType(name),
looseName: nameApi.dataArgsType(name),
dataEnumDiscriminator: nameApi.dataEnumDiscriminator(name),
getVariant: (variant: string) => nameApi.dataEnumVariant(variant),
dataEnumFunction: nameApi.dataEnumFunction(name),
isDataEnumFunction: nameApi.isDataEnumFunction(name),
discriminatedUnionDiscriminator:
nameApi.discriminatedUnionDiscriminator(name),
getVariant: (variant: string) => nameApi.discriminatedUnionVariant(variant),
discriminatedUnionFunction: nameApi.discriminatedUnionFunction(name),
isDiscriminatedUnionFunction: nameApi.isDiscriminatedUnionFunction(name),
typeNode,
}).addImports('solanaCodecsDataStructures', [
'GetDataEnumKindContent',
'GetDataEnumKind',
'GetDiscriminatedUnionVariantContent',
'GetDiscriminatedUnionVariant',
]);
}
13 changes: 8 additions & 5 deletions src/renderers/js-experimental/getRenderMapVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import {
getProgramErrorsFragment,
getProgramFragment,
getProgramInstructionsFragment,
getTypeDataEnumHelpersFragment,
getTypeDiscriminatedUnionHelpersFragment,
getTypeWithCodecFragment,
} from './fragments';
import {
Expand Down Expand Up @@ -447,10 +447,13 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) {
};

const typeWithCodecFragment = getTypeWithCodecFragment(scope);
const typeDataEnumHelpersFragment =
getTypeDataEnumHelpersFragment(scope);
const typeDiscriminatedUnionHelpersFragment =
getTypeDiscriminatedUnionHelpersFragment(scope);
const imports = new ImportMap()
.mergeWith(typeWithCodecFragment, typeDataEnumHelpersFragment)
.mergeWith(
typeWithCodecFragment,
typeDiscriminatedUnionHelpersFragment
)
.remove('generatedTypes', [
nameApi.dataType(node.name),
nameApi.dataArgsType(node.name),
Expand All @@ -467,7 +470,7 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) {
generatedTypes: '.',
}),
typeWithCodecFragment,
typeDataEnumHelpersFragment,
typeDiscriminatedUnionHelpersFragment,
})
);
},
Expand Down
42 changes: 27 additions & 15 deletions src/renderers/js-experimental/getTypeManifestVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,28 +171,28 @@ export function getTypeManifestVisitor(input: {
);
}
const variantNames = enumType.variants.map(({ name }) =>
nameApi.scalarEnumVariant(name)
nameApi.enumVariant(name)
);
return {
isEnum: true,
strictType: fragment(`{ ${variantNames.join(', ')} }`),
looseType: fragment(`{ ${variantNames.join(', ')} }`),
encoder: fragment(
`getScalarEnumEncoder(${
`getEnumEncoder(${
currentParentName.strict + encoderOptionsAsString
})`,
encoderImports.add(
'solanaCodecsDataStructures',
'getScalarEnumEncoder'
'getEnumEncoder'
)
),
decoder: fragment(
`getScalarEnumDecoder(${
`getEnumDecoder(${
currentParentName.strict + decoderOptionsAsString
})`,
decoderImports.add(
'solanaCodecsDataStructures',
'getScalarEnumDecoder'
'getEnumDecoder'
)
),
};
Expand All @@ -205,24 +205,32 @@ export function getTypeManifestVisitor(input: {
);
mergedManifest.encoder
.mapRender(
(r) => `getDataEnumEncoder([${r}]${encoderOptionsAsString})`
(r) =>
`getDiscriminatedUnionEncoder([${r}]${encoderOptionsAsString})`
)
.mergeImportsWith(encoderImports)
.addImports('solanaCodecsDataStructures', ['getDataEnumEncoder']);
.addImports('solanaCodecsDataStructures', [
'getDiscriminatedUnionEncoder',
]);
mergedManifest.decoder
.mapRender(
(r) => `getDataEnumDecoder([${r}]${decoderOptionsAsString})`
(r) =>
`getDiscriminatedUnionDecoder([${r}]${decoderOptionsAsString})`
)
.mergeImportsWith(decoderImports)
.addImports('solanaCodecsDataStructures', ['getDataEnumDecoder']);
.addImports('solanaCodecsDataStructures', [
'getDiscriminatedUnionDecoder',
]);
return mergedManifest;
},

visitEnumEmptyVariantType(enumEmptyVariantType) {
const discriminator = nameApi.dataEnumDiscriminator(
const discriminator = nameApi.discriminatedUnionDiscriminator(
enumEmptyVariantType.name
);
const name = nameApi.discriminatedUnionVariant(
enumEmptyVariantType.name
);
const name = nameApi.dataEnumVariant(enumEmptyVariantType.name);
const kindAttribute = `${discriminator}: "${name}"`;
return {
isEnum: false,
Expand All @@ -240,10 +248,12 @@ export function getTypeManifestVisitor(input: {
},

visitEnumStructVariantType(enumStructVariantType, { self }) {
const discriminator = nameApi.dataEnumDiscriminator(
const discriminator = nameApi.discriminatedUnionDiscriminator(
enumStructVariantType.name
);
const name = nameApi.discriminatedUnionVariant(
enumStructVariantType.name
);
const name = nameApi.dataEnumVariant(enumStructVariantType.name);
const kindAttribute = `${discriminator}: "${name}"`;
const structManifest = visit(enumStructVariantType.struct, self);
structManifest.strictType.mapRender(
Expand All @@ -258,10 +268,12 @@ export function getTypeManifestVisitor(input: {
},

visitEnumTupleVariantType(enumTupleVariantType, { self }) {
const discriminator = nameApi.dataEnumDiscriminator(
const discriminator = nameApi.discriminatedUnionDiscriminator(
enumTupleVariantType.name
);
const name = nameApi.discriminatedUnionVariant(
enumTupleVariantType.name
);
const name = nameApi.dataEnumVariant(enumTupleVariantType.name);
const kindAttribute = `${discriminator}: "${name}"`;
const struct = structTypeNode([
structFieldTypeNode({
Expand Down
20 changes: 10 additions & 10 deletions src/renderers/js-experimental/nameTransformers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ export type NameTransformerKey =
| 'accountFetchFromSeedsFunction'
| 'accountFetchMaybeFromSeedsFunction'
| 'accountGetSizeFunction'
| 'scalarEnumVariant'
| 'dataEnumDiscriminator'
| 'dataEnumVariant'
| 'dataEnumFunction'
| 'isDataEnumFunction'
| 'enumVariant'
| 'discriminatedUnionDiscriminator'
| 'discriminatedUnionVariant'
| 'discriminatedUnionFunction'
| 'isDiscriminatedUnionFunction'
| 'instructionAsyncInputType'
| 'instructionSyncInputType'
| 'instructionType'
Expand Down Expand Up @@ -111,11 +111,11 @@ export const DEFAULT_NAME_TRANSFORMERS: NameTransformers = {
accountFetchMaybeFromSeedsFunction: (name) =>
`fetchMaybe${pascalCase(name)}FromSeeds`,
accountGetSizeFunction: (name) => `get${pascalCase(name)}Size`,
scalarEnumVariant: (name) => `${pascalCase(name)}`,
dataEnumDiscriminator: () => '__kind',
dataEnumVariant: (name) => `${pascalCase(name)}`,
dataEnumFunction: (name) => `${camelCase(name)}`,
isDataEnumFunction: (name) => `is${pascalCase(name)}`,
enumVariant: (name) => `${pascalCase(name)}`,
discriminatedUnionDiscriminator: () => '__kind',
discriminatedUnionVariant: (name) => `${pascalCase(name)}`,
discriminatedUnionFunction: (name) => `${camelCase(name)}`,
isDiscriminatedUnionFunction: (name) => `is${pascalCase(name)}`,
instructionAsyncInputType: (name) => `${pascalCase(name)}AsyncInput`,
instructionSyncInputType: (name) => `${pascalCase(name)}Input`,
instructionType: (name) => `${pascalCase(name)}Instruction`,
Expand Down
6 changes: 3 additions & 3 deletions src/renderers/js-experimental/renderValueNodeVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export function renderValueNodeVisitor(input: {
},
visitEnumValue(node) {
const enumName = nameApi.dataType(node.enum.name);
const enumFunction = nameApi.dataEnumFunction(node.enum.name);
const enumFunction = nameApi.discriminatedUnionFunction(node.enum.name);
const importFrom = node.enum.importFrom ?? 'generatedTypes';

const enumNode = linkables.get(node.enum)?.type;
Expand All @@ -34,14 +34,14 @@ export function renderValueNodeVisitor(input: {
: !nonScalarEnums.includes(node.enum.name);

if (!node.value && isScalar) {
const variantName = nameApi.scalarEnumVariant(node.variant);
const variantName = nameApi.enumVariant(node.variant);
return fragment(`${enumName}.${variantName}`).addImports(
importFrom,
enumName
);
}

const variantName = nameApi.dataEnumVariant(node.variant);
const variantName = nameApi.discriminatedUnionVariant(node.variant);
if (!node.value) {
return fragment(`${enumFunction}('${variantName}')`).addImports(
importFrom,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
{{ imports }}

{{ typeWithCodecFragment }}
{{ typeDataEnumHelpersFragment }}
{{ typeDiscriminatedUnionHelpersFragment }}
{% endblock %}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import {
Decoder,
Encoder,
combineCodec,
getScalarEnumDecoder,
getScalarEnumEncoder,
getEnumDecoder,
getEnumEncoder,
} from '@solana/codecs';

export enum AuthorityType {
Expand All @@ -25,11 +25,11 @@ export enum AuthorityType {
export type AuthorityTypeArgs = AuthorityType;

export function getAuthorityTypeEncoder(): Encoder<AuthorityTypeArgs> {
return getScalarEnumEncoder(AuthorityType);
return getEnumEncoder(AuthorityType);
}

export function getAuthorityTypeDecoder(): Decoder<AuthorityType> {
return getScalarEnumDecoder(AuthorityType);
return getEnumDecoder(AuthorityType);
}

export function getAuthorityTypeCodec(): Codec<
Expand Down
8 changes: 4 additions & 4 deletions test/packages/js-experimental/src/generated/types/burnArgs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import {
Decoder,
Encoder,
combineCodec,
getScalarEnumDecoder,
getScalarEnumEncoder,
getEnumDecoder,
getEnumEncoder,
getU64Decoder,
getU64Encoder,
} from '@solana/codecs';
Expand All @@ -24,11 +24,11 @@ export enum BurnArgs {
export type BurnArgsArgs = BurnArgs;

export function getBurnArgsEncoder(): Encoder<BurnArgsArgs> {
return getScalarEnumEncoder(BurnArgs, { size: getU64Encoder() });
return getEnumEncoder(BurnArgs, { size: getU64Encoder() });
}

export function getBurnArgsDecoder(): Decoder<BurnArgs> {
return getScalarEnumDecoder(BurnArgs, { size: getU64Decoder() });
return getEnumDecoder(BurnArgs, { size: getU64Decoder() });
}

export function getBurnArgsCodec(): Codec<BurnArgsArgs, BurnArgs> {
Expand Down
Loading

0 comments on commit 0434144

Please sign in to comment.