diff --git a/.changeset/two-spoons-wonder.md b/.changeset/two-spoons-wonder.md new file mode 100644 index 00000000..090b6410 --- /dev/null +++ b/.changeset/two-spoons-wonder.md @@ -0,0 +1,5 @@ +--- +"@codama/spec": minor +--- + +Add v1/docs documentation and `@codama/spec/docs` docs generator. Define shape and enrich nodes with typescript examples. diff --git a/generators/docs/index.ts b/generators/docs/index.ts index 3fb01791..09f41b2f 100644 --- a/generators/docs/index.ts +++ b/generators/docs/index.ts @@ -4,6 +4,9 @@ * Runs the docs generator over the v1 spec, then writes the emitted mdx tree to * `v1/docs/` (plain page bodies, relative `.mdx` links, `index` basenames). CI re-runs this and fails if * the result differs from what is committed, keeping the docs artifact in lockstep with the spec source. + * + * The same model also feeds the Fumadocs app tree under `docs/content/spec//`, which adds YAML + * frontmatter per page plus the `meta.json` sidecars the sidebar needs. */ import path from 'node:path'; diff --git a/src/api/defineNode.ts b/src/api/defineNode.ts index 5e016859..8ecfc4f3 100644 --- a/src/api/defineNode.ts +++ b/src/api/defineNode.ts @@ -14,6 +14,7 @@ * meta-model itself just stores a flat list. */ +import type { DocExamples } from './example'; import type { AttributeSpec, NodeSpec } from './types'; export interface DefineNodeOptions { @@ -24,8 +25,11 @@ export interface DefineNodeOptions { * via `attribute(...)` or `optionalAttribute(...)`. */ readonly attributes: readonly AttributeSpec[]; - /** Free-form examples (shape defined per spec major version). */ - readonly examples?: readonly unknown[]; + /** + * Documentation examples for the node. + * Construct each via `example(...)`. + * */ + readonly examples?: DocExamples; } export function defineNode(kind: string, options: DefineNodeOptions): NodeSpec { diff --git a/src/api/example.ts b/src/api/example.ts new file mode 100644 index 00000000..5a112bb6 --- /dev/null +++ b/src/api/example.ts @@ -0,0 +1,126 @@ +/** + * Examples for spec nodes - the shape plus the helpers used to author and validate it. + * + * Each node may carry a list of worked examples rendered into its docs page. + * Authors write a snippet as a single template literal. + * `code()` dedents it and splits it into one entry per source line, + * so the serialized `spec.json` stores `content` as a line array. + * That keeps committed diffs readable line-by-line. + * Renderers rejoin the lines with `\n` before emitting a fenced block. + * + * ## The `.examples.ts` file convention: + * + * Examples live in a sibling file next to each node definition. + * Each file: + * + * - is named after the node file with an `.examples.ts` suffix + * (`AmountTypeNode.ts` -> `AmountTypeNode.examples.ts`) + * - writes each snippet as a template literal passed straight to `code()`, so the + * snippet reads like real code and `dedent()` strips any source indentation + * - exports a single `DocExamples` array named `examples` + * + * The node file imports that array and hands it to `defineNode`: + * + * ```ts + * // AmountTypeNode.examples.ts + * import { code, example, type DocExamples } from '../../../api'; + * + * export const examples: DocExamples = [ + * example('2-decimals USD amount', code('typescript', ` + * amountTypeNode(numberTypeNode('u32'), 2, 'USD'); + * + * // 0.01 USD => 0x01000000 + * `)), + * ]; + * ``` + * + * ```ts + * // AmountTypeNode.ts + * import { examples } from './AmountTypeNode.examples'; + * + * export const amountTypeNode = defineNode('amountTypeNode', { + * docs: ['...'], + * attributes: ['...'], + * examples, + * }); + * ``` + */ + +/** Languages the spec ships example snippets for. */ +export type CodeLanguage = 'typescript' | 'rust'; + +/** A single code snippet for one language. */ +export interface CodeBlock { + readonly language: CodeLanguage; + readonly content: readonly string[]; +} + +/** + * One documented case for a node. + * `docs` mirrors the node and attribute `docs` convention. + */ +export interface DocExample { + readonly title: string; + readonly docs?: readonly string[]; + readonly code: readonly CodeBlock[]; +} + +/** The example collection attached to a node through `NodeSpec.examples`. */ +export type DocExamples = readonly DocExample[]; + +/** Options for `example()`. */ +export interface ExampleOptions { + /** Free-form prose paragraphs shown under the example title. */ + readonly docs?: readonly string[]; +} + +/** + * Build a `CodeBlock` from a template-literal snippet. + * + * The content is dedented then split into one entry per line. + * Dedent removes the common leading indentation shared by all non-blank lines. + * Use spaces, not tabs, for indentation. + */ +export function code(language: CodeLanguage, content: string): CodeBlock { + return Object.freeze({ + language, + content: Object.freeze(dedent(content).split('\n')), + }); +} + +/** + * Build a `DocExample` from a title and one or more code blocks. + * + * Pass a single `CodeBlock` for the common one-language case, + * or an array to show the same case in several languages. + * Optional `docs` render as prose under the title. + */ +export function example( + title: string, + blocks: CodeBlock | readonly CodeBlock[], + options: ExampleOptions = {}, +): DocExample { + const list = 'language' in blocks ? [blocks] : blocks; + return Object.freeze({ + title, + ...(options.docs !== undefined ? { docs: Object.freeze([...options.docs]) } : {}), + code: Object.freeze([...list]), + }); +} + +/** + * Remove the common leading indentation shared by all non-blank lines. + * Trim a single leading newline plus any trailing whitespace. + * Relative indentation is kept. + * Assumes space indentation - mixing tabs and spaces makes the common prefix ambiguous. + */ +function dedent(text: string): string { + // Drop the leading newline and trailing whitespace, then split into lines. + const lines = text.replace(/^\n/, '').replace(/\s+$/, '').split('\n'); + // Measure the leading-whitespace width of each non-blank line (blanks would falsely force a 0 common indent). + const indents = lines.filter(line => line.trim().length > 0).map(line => line.match(/^[ \t]*/)?.[0].length ?? 0); + // The shared indentation is the smallest of those widths (0 when every line is blank). + const common = indents.length > 0 ? Math.min(...indents) : 0; + // Strip that shared prefix from every line, keeping relative indentation intact. + return lines.map(line => line.slice(common)).join('\n'); +} diff --git a/src/api/index.ts b/src/api/index.ts index ba85c4ec..9153723b 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -12,6 +12,7 @@ export * from './defineEnumeration'; export * from './defineNestedUnion'; export * from './defineNode'; export * from './defineUnion'; +export * from './example'; export * from './primitives'; export * from './semanticAliases'; export * from './validate'; diff --git a/src/api/public.ts b/src/api/public.ts index 39d679c2..40adb735 100644 --- a/src/api/public.ts +++ b/src/api/public.ts @@ -7,6 +7,7 @@ * included here — they live in `./index.ts` for internal use only. */ +export type { CodeBlock, CodeLanguage, DocExample, DocExamples } from './example'; export type { AttributeSpec, CategorySpec, diff --git a/src/api/types.ts b/src/api/types.ts index aa6a8065..d7dc1932 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -9,6 +9,8 @@ * enumerations, nested unions, categories). */ +import type { DocExamples } from './example'; + export type IntegerWidth = 'i8' | 'i16' | 'i32' | 'i64' | 'i128' | 'u8' | 'u16' | 'u32' | 'u64' | 'u128'; export type FloatWidth = 'f32' | 'f64'; @@ -102,8 +104,8 @@ export interface NodeSpec { readonly kind: string; readonly docs?: readonly string[]; readonly attributes: readonly AttributeSpec[]; - /** Free-form examples (shape defined per spec major version). */ - readonly examples: readonly unknown[]; + /** Worked documentation examples for this node - see `DocExample`. */ + readonly examples: DocExamples; } /** A member of a union — either a node by name, or another union by name. */ diff --git a/src/docs/render/renderPages.ts b/src/docs/render/renderPages.ts index 445a6248..c69f7b68 100644 --- a/src/docs/render/renderPages.ts +++ b/src/docs/render/renderPages.ts @@ -3,6 +3,8 @@ import { pascalCase } from '@codama/fragments'; import type { AttributeSpec, CategorySpec, + DocExample, + DocExamples, EnumerationSpec, NestedUnionSpec, NodeSpec, @@ -58,6 +60,8 @@ export function renderNodePage(node: NodeSpec, ctx: RenderCtx): DocPage { childRows.length ? `${markup.heading(3, 'Children')}${BLOCK_SEPARATOR}${markup.table(cols, childRows)}` : undefined, + // Examples section + renderExamples(node.examples, markup), ]; return { ref, @@ -66,6 +70,27 @@ export function renderNodePage(node: NodeSpec, ctx: RenderCtx): DocPage { }; } +/** Render all Node examples. Every language carried by the spec is rendered. */ +function renderExamples(examples: DocExamples, markup: MarkupRenderer): string | undefined { + const rendered = examples.map(example => renderExample(example, markup)).filter(block => block !== undefined); + if (!rendered.length) return undefined; + return [markup.heading(2, 'Examples'), ...rendered].join(BLOCK_SEPARATOR); +} + +/** Render each example. An example carrying no code block renders nothing rather than a bare heading. */ +function renderExample(example: DocExample, markup: MarkupRenderer): string | undefined { + if (!example.code.length) return undefined; + const parts: (string | undefined)[] = [ + // header + markup.heading(3, example.title), + // description + renderSpecDocs(example.docs, markup), + // code blocks + ...example.code.map(code => markup.codeBlock(code.language, code.content.join('\n'))), + ]; + return parts.filter(Boolean).join(BLOCK_SEPARATOR); +} + export function renderUnionPage(union: UnionSpec, ctx: RenderCtx): DocPage { const { markup } = ctx; const ref: DocRef = { kind: 'union', name: union.name }; diff --git a/src/v1/nodes/AccountNode.examples.ts b/src/v1/nodes/AccountNode.examples.ts new file mode 100644 index 00000000..74b9dc73 --- /dev/null +++ b/src/v1/nodes/AccountNode.examples.ts @@ -0,0 +1,49 @@ +import { code, example, type DocExamples } from '../../api'; + +export const examples: DocExamples = [ + example( + 'A fixed-size account', + code( + 'typescript', + ` +const node = accountNode({ + name: 'token', + data: structTypeNode([ + structFieldTypeNode({ name: 'mint', type: publicKeyTypeNode() }), + structFieldTypeNode({ name: 'owner', type: publicKeyTypeNode() }), + structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') }), + ]), + discriminators: [sizeDiscriminatorNode(72)], + size: 72, +}); +`, + ), + ), + example( + 'An account with a linked PDA', + code( + 'typescript', + ` +programNode({ + name: 'myProgram', + accounts: [ + accountNode({ + name: 'token', + data: structTypeNode([structFieldTypeNode({ name: 'authority', type: publicKeyTypeNode() })]), + pda: pdaLinkNode('myPda'), + }), + ], + pdas: [ + pdaNode({ + name: 'myPda', + seeds: [ + constantPdaSeedNodeFromString('utf8', 'token'), + variablePdaSeedNode('authority', publicKeyTypeNode()), + ], + }), + ], +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/AccountNode.ts b/src/v1/nodes/AccountNode.ts index 76ef6513..cbb28c6e 100644 --- a/src/v1/nodes/AccountNode.ts +++ b/src/v1/nodes/AccountNode.ts @@ -10,6 +10,7 @@ import { stringIdentifier, union, } from '../../api'; +import { examples } from './AccountNode.examples'; export const accountNode = defineNode('accountNode', { docs: [ @@ -38,4 +39,5 @@ export const accountNode = defineNode('accountNode', { ], }), ], + examples, }); diff --git a/src/v1/nodes/ConstantNode.examples.ts b/src/v1/nodes/ConstantNode.examples.ts new file mode 100644 index 00000000..2fdb61e1 --- /dev/null +++ b/src/v1/nodes/ConstantNode.examples.ts @@ -0,0 +1,33 @@ +import { code, example, type DocExamples } from '../../api'; + +export const examples: DocExamples = [ + example( + 'Numeric Constant', + code( + 'typescript', + ` +const node = constantNode('maxSize', numberTypeNode('u32'), numberValueNode(100)); +`, + ), + ), + example( + 'Bytes Constant', + code( + 'typescript', + ` +const node = constantNode('seedPrefix', bytesTypeNode(), bytesValueNode('base16', '74657374')); +`, + ), + ), + example( + 'With Documentation', + code( + 'typescript', + ` +const node = constantNode('maxItems', numberTypeNode('u64'), numberValueNode(1000), [ + 'The maximum number of items allowed.', +]); +`, + ), + ), +]; diff --git a/src/v1/nodes/ConstantNode.ts b/src/v1/nodes/ConstantNode.ts index baea0bab..071fbd90 100644 --- a/src/v1/nodes/ConstantNode.ts +++ b/src/v1/nodes/ConstantNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, docs, optionalAttribute, stringIdentifier, union } from '../../api'; +import { examples } from './ConstantNode.examples'; export const constantNode = defineNode('constantNode', { docs: ['A named constant exposed by the program: a typed value associated with a name.'], @@ -16,4 +17,5 @@ export const constantNode = defineNode('constantNode', { docs: ['The concrete value of the constant.'], }), ], + examples, }); diff --git a/src/v1/nodes/DefinedTypeNode.examples.ts b/src/v1/nodes/DefinedTypeNode.examples.ts new file mode 100644 index 00000000..572058a4 --- /dev/null +++ b/src/v1/nodes/DefinedTypeNode.examples.ts @@ -0,0 +1,20 @@ +import { code, example, type DocExamples } from '../../api'; + +export const examples: DocExamples = [ + example( + 'Create a defined type node from an input object', + code( + 'typescript', + ` +const node = definedTypeNode({ + name: 'person', + docs: ['This type describes a Person.'], + type: structTypeNode([ + structFieldTypeNode({ name: 'name', type: stringTypeNode('utf8') }), + structFieldTypeNode({ name: 'age', type: numberTypeNode('u8') }), + ]), +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/DefinedTypeNode.ts b/src/v1/nodes/DefinedTypeNode.ts index 1aec2c8e..4af5097b 100644 --- a/src/v1/nodes/DefinedTypeNode.ts +++ b/src/v1/nodes/DefinedTypeNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, docs, optionalAttribute, stringIdentifier, union } from '../../api'; +import { examples } from './DefinedTypeNode.examples'; export const definedTypeNode = defineNode('definedTypeNode', { docs: ['A reusable named type that can be referenced by `definedTypeLinkNode` from elsewhere in the IDL.'], @@ -13,4 +14,5 @@ export const definedTypeNode = defineNode('definedTypeNode', { docs: ['The type definition.'], }), ], + examples, }); diff --git a/src/v1/nodes/ErrorNode.examples.ts b/src/v1/nodes/ErrorNode.examples.ts new file mode 100644 index 00000000..24aebed6 --- /dev/null +++ b/src/v1/nodes/ErrorNode.examples.ts @@ -0,0 +1,17 @@ +import { code, example, type DocExamples } from '../../api'; + +export const examples: DocExamples = [ + example( + 'Create an error node from an input object', + code( + 'typescript', + ` +const node = errorNode({ + name: 'invalidAmountArgument', + code: 1, + message: 'The amount argument is invalid.', +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/ErrorNode.ts b/src/v1/nodes/ErrorNode.ts index 00ccb771..a9d9b592 100644 --- a/src/v1/nodes/ErrorNode.ts +++ b/src/v1/nodes/ErrorNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, docs, optionalAttribute, string, stringIdentifier, u32 } from '../../api'; +import { examples } from './ErrorNode.examples'; export const errorNode = defineNode('errorNode', { docs: ['A program error — a numeric code paired with a name and human-readable message.'], @@ -16,4 +17,5 @@ export const errorNode = defineNode('errorNode', { docs: ['Markdown documentation for the error.'], }), ], + examples, }); diff --git a/src/v1/nodes/EventNode.examples.ts b/src/v1/nodes/EventNode.examples.ts new file mode 100644 index 00000000..359c5e25 --- /dev/null +++ b/src/v1/nodes/EventNode.examples.ts @@ -0,0 +1,38 @@ +import { code, example, type DocExamples } from '../../api'; + +export const examples: DocExamples = [ + example( + 'An event with a struct payload', + code( + 'typescript', + ` +eventNode({ + name: 'transferEvent', + data: structTypeNode([ + structFieldTypeNode({ name: 'authority', type: publicKeyTypeNode() }), + structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') }), + ]), +}); +`, + ), + ), + example( + 'An event with a hidden prefix discriminator', + code( + 'typescript', + ` +eventNode({ + name: 'transferEvent', + data: hiddenPrefixTypeNode(structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') })]), [ + constantValueNode(fixedSizeTypeNode(bytesTypeNode(), 8), bytesValueNode('base16', '0102030405060708')), + ]), + discriminators: [ + constantDiscriminatorNode( + constantValueNode(fixedSizeTypeNode(bytesTypeNode(), 8), bytesValueNode('base16', '0102030405060708')), + ), + ], +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/EventNode.ts b/src/v1/nodes/EventNode.ts index c6d33686..660cccd8 100644 --- a/src/v1/nodes/EventNode.ts +++ b/src/v1/nodes/EventNode.ts @@ -1,4 +1,5 @@ import { array, attribute, defineNode, docs, optionalAttribute, stringIdentifier, union } from '../../api'; +import { examples } from './EventNode.examples'; export const eventNode = defineNode('eventNode', { docs: ['A program event: its data shape and optional discriminators used to identify it on the wire.'], @@ -18,4 +19,5 @@ export const eventNode = defineNode('eventNode', { ], }), ], + examples, }); diff --git a/src/v1/nodes/InstructionAccountNode.examples.ts b/src/v1/nodes/InstructionAccountNode.examples.ts new file mode 100644 index 00000000..3b3b3627 --- /dev/null +++ b/src/v1/nodes/InstructionAccountNode.examples.ts @@ -0,0 +1,33 @@ +import { code, example, type DocExamples } from '../../api'; + +export const examples: DocExamples = [ + example( + 'An optional account', + code( + 'typescript', + ` +instructionAccountNode({ + name: 'freezeAuthority', + isWritable: false, + isSigner: false, + isOptional: true, + docs: ['The freeze authority to set on the asset, if any.'], +}); +`, + ), + ), + example( + 'An optional signer account', + code( + 'typescript', + ` +instructionAccountNode({ + name: 'owner', + isWritable: true, + isSigner: 'either', + docs: ['The owner of the asset. The owner must only sign the transaction if the asset is being updated.'], +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/InstructionAccountNode.ts b/src/v1/nodes/InstructionAccountNode.ts index 7eafc523..262df809 100644 --- a/src/v1/nodes/InstructionAccountNode.ts +++ b/src/v1/nodes/InstructionAccountNode.ts @@ -9,6 +9,7 @@ import { stringIdentifier, union, } from '../../api'; +import { examples } from './InstructionAccountNode.examples'; export const instructionAccountNode = defineNode('instructionAccountNode', { docs: [ @@ -46,4 +47,5 @@ export const instructionAccountNode = defineNode('instructionAccountNode', { docs: ['Display metadata describing how the account is presented.'], }), ], + examples, }); diff --git a/src/v1/nodes/InstructionArgumentNode.examples.ts b/src/v1/nodes/InstructionArgumentNode.examples.ts new file mode 100644 index 00000000..e286a02c --- /dev/null +++ b/src/v1/nodes/InstructionArgumentNode.examples.ts @@ -0,0 +1,31 @@ +import { code, example, type DocExamples } from '../../api'; + +export const examples: DocExamples = [ + example( + 'An argument with a default value', + code( + 'typescript', + ` +instructionArgumentNode({ + name: 'amount', + type: numberTypeNode('u64'), + defaultValue: numberValueNode(0), +}); +`, + ), + ), + example( + 'An argument with an omitted default value', + code( + 'typescript', + ` +instructionArgumentNode({ + name: 'instructionDiscriminator', + type: numberTypeNode('u8'), + defaultValue: numberValueNode(42), + defaultValueStrategy: 'omitted', +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/InstructionArgumentNode.ts b/src/v1/nodes/InstructionArgumentNode.ts index 5f29c932..d591d4be 100644 --- a/src/v1/nodes/InstructionArgumentNode.ts +++ b/src/v1/nodes/InstructionArgumentNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, docs, enumeration, node, optionalAttribute, stringIdentifier, union } from '../../api'; +import { examples } from './InstructionArgumentNode.examples'; export const instructionArgumentNode = defineNode('instructionArgumentNode', { docs: ['A named argument of an instruction, with its type and an optional default value.'], @@ -22,4 +23,5 @@ export const instructionArgumentNode = defineNode('instructionArgumentNode', { docs: ['Display metadata describing how the argument is presented.'], }), ], + examples, }); diff --git a/src/v1/nodes/InstructionByteDeltaNode.examples.ts b/src/v1/nodes/InstructionByteDeltaNode.examples.ts new file mode 100644 index 00000000..4db3c46a --- /dev/null +++ b/src/v1/nodes/InstructionByteDeltaNode.examples.ts @@ -0,0 +1,31 @@ +import { code, example, type DocExamples } from '../../api'; + +export const examples: DocExamples = [ + example( + 'A byte delta that represents a new account', + code( + 'typescript', + ` +instructionByteDeltaNode(accountLinkNode('token')); +`, + ), + ), + example( + 'A byte delta that represents an account deletion', + code( + 'typescript', + ` +instructionByteDeltaNode(accountLinkNode('token'), { subtract: true }); +`, + ), + ), + example( + 'A byte delta that uses an argument value to increase the space of an account', + code( + 'typescript', + ` +instructionByteDeltaNode(argumentValueNode('additionalSpace'), { withHeader: false }); +`, + ), + ), +]; diff --git a/src/v1/nodes/InstructionByteDeltaNode.ts b/src/v1/nodes/InstructionByteDeltaNode.ts index 922dfba9..903cf23e 100644 --- a/src/v1/nodes/InstructionByteDeltaNode.ts +++ b/src/v1/nodes/InstructionByteDeltaNode.ts @@ -1,4 +1,5 @@ import { attribute, boolean, defineNode, optionalAttribute, union } from '../../api'; +import { examples } from './InstructionByteDeltaNode.examples'; export const instructionByteDeltaNode = defineNode('instructionByteDeltaNode', { docs: [ @@ -17,4 +18,5 @@ export const instructionByteDeltaNode = defineNode('instructionByteDeltaNode', { ], }), ], + examples, }); diff --git a/src/v1/nodes/InstructionNode.examples.ts b/src/v1/nodes/InstructionNode.examples.ts new file mode 100644 index 00000000..0305dadd --- /dev/null +++ b/src/v1/nodes/InstructionNode.examples.ts @@ -0,0 +1,174 @@ +import { code, example, type DocExamples } from '../../api'; + +export const examples: DocExamples = [ + example( + 'An instruction with a u8 discriminator', + code( + 'typescript', + ` +instructionNode({ + name: 'increment', + accounts: [ + instructionAccountNode({ name: 'counter', isWritable: true, isSigner: true }), + instructionAccountNode({ name: 'authority', isWritable: false, isSigner: false }), + ], + arguments: [ + instructionArgumentNode({ + name: 'discriminator', + type: numberTypeNode('u8'), + defaultValue: numberValueNode(42), + defaultValueStrategy: 'omitted', + }), + ], +}); +`, + ), + ), + example( + 'An instruction that creates a new account', + code( + 'typescript', + ` +instructionNode({ + name: 'createCounter', + accounts: [ + instructionAccountNode({ name: 'counter', isWritable: true, isSigner: true }), + instructionAccountNode({ name: 'authority', isWritable: false, isSigner: false }), + ], + byteDeltas: [instructionByteDeltaNode(accountLinkNode('counter'))], +}); +`, + ), + ), + example( + 'An instruction with omitted optional accounts', + code( + 'typescript', + ` +instructionNode({ + name: 'initialize', + accounts: [ + instructionAccountNode({ name: 'counter', isWritable: true, isSigner: true }), + instructionAccountNode({ name: 'authority', isWritable: false, isSigner: false }), + instructionAccountNode({ name: 'freezeAuthority', isWritable: false, isSigner: false, isOptional: true }), + ], + optionalAccountStrategy: 'omitted', +}); +`, + ), + ), + example( + 'An instruction with remaining signers', + code( + 'typescript', + ` +instructionNode({ + name: 'multisigIncrement', + accounts: [instructionAccountNode({ name: 'counter', isWritable: true, isSigner: false })], + remainingAccounts: [instructionRemainingAccountsNode(argumentValueNode('authorities'), { isSigner: true })], +}); +`, + ), + ), + example( + 'An instruction with nested versioned instructions', + code( + 'typescript', + ` +instructionNode({ + name: 'increment', + accounts: [ + instructionAccountNode({ name: 'counter', isWritable: true, isSigner: 'either' }), + instructionAccountNode({ name: 'authority', isWritable: false, isSigner: true }), + ], + arguments: [ + instructionArgumentNode({ name: 'version', type: numberTypeNode('u8') }), + instructionArgumentNode({ name: 'amount', type: numberTypeNode('u8') }), + ], + subInstructions: [ + instructionNode({ + name: 'incrementV1', + accounts: [instructionAccountNode({ name: 'counter', isWritable: true, isSigner: true })], + arguments: [ + instructionArgumentNode({ + name: 'version', + type: numberTypeNode('u8'), + defaultValue: numberValueNode(0), + defaultValueStrategy: 'omitted', + }), + instructionArgumentNode({ name: 'amount', type: numberTypeNode('u8') }), + ], + }), + instructionNode({ + name: 'incrementV2', + accounts: [ + instructionAccountNode({ name: 'counter', isWritable: true, isSigner: false }), + instructionAccountNode({ name: 'authority', isWritable: false, isSigner: true }), + ], + arguments: [ + instructionArgumentNode({ + name: 'version', + type: numberTypeNode('u8'), + defaultValue: numberValueNode(1), + defaultValueStrategy: 'omitted', + }), + instructionArgumentNode({ name: 'amount', type: numberTypeNode('u8') }), + ], + }), + ], +}); +`, + ), + ), + example( + 'A deprecated instruction', + code( + 'typescript', + ` +instructionNode({ + name: 'oldIncrement', + status: instructionStatusNode( + 'deprecated', + 'Use the \`increment\` instruction instead. This will be removed in v3.0.0.', + ), + accounts: [instructionAccountNode({ name: 'counter', isWritable: true, isSigner: false })], + arguments: [instructionArgumentNode({ name: 'amount', type: numberTypeNode('u8') })], +}); +`, + ), + ), + example( + 'An archived instruction', + code( + 'typescript', + ` +instructionNode({ + name: 'legacyTransfer', + status: instructionStatusNode( + 'archived', + 'This instruction was removed in v2.0.0. It is kept here for historical parsing.', + ), + accounts: [ + instructionAccountNode({ name: 'source', isWritable: true, isSigner: true }), + instructionAccountNode({ name: 'destination', isWritable: true, isSigner: false }), + ], + arguments: [instructionArgumentNode({ name: 'amount', type: numberTypeNode('u64') })], +}); +`, + ), + ), + example( + 'A draft instruction', + code( + 'typescript', + ` +instructionNode({ + name: 'experimentalFeature', + status: instructionStatusNode('draft', 'This instruction is under development and may change.'), + accounts: [instructionAccountNode({ name: 'config', isWritable: true, isSigner: true })], + arguments: [], +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/InstructionNode.ts b/src/v1/nodes/InstructionNode.ts index 45ad23b0..d6ecbcb2 100644 --- a/src/v1/nodes/InstructionNode.ts +++ b/src/v1/nodes/InstructionNode.ts @@ -9,6 +9,7 @@ import { stringIdentifier, union, } from '../../api'; +import { examples } from './InstructionNode.examples'; export const instructionNode = defineNode('instructionNode', { docs: [ @@ -66,4 +67,5 @@ export const instructionNode = defineNode('instructionNode', { docs: ['Namespaced plugins with custom structured data.'], }), ], + examples, }); diff --git a/src/v1/nodes/InstructionRemainingAccountsNode.examples.ts b/src/v1/nodes/InstructionRemainingAccountsNode.examples.ts new file mode 100644 index 00000000..ea9a169d --- /dev/null +++ b/src/v1/nodes/InstructionRemainingAccountsNode.examples.ts @@ -0,0 +1,41 @@ +import { code, example, type DocExamples } from '../../api'; + +export const examples: DocExamples = [ + example( + 'Optional remaining signers', + code( + 'typescript', + ` +instructionRemainingAccountsNode(argumentValueNode('authorities'), { + isSigner: true, + isOptional: true, +}); +`, + ), + ), + example( + 'Remaining accounts that may or may not be signers', + code( + 'typescript', + ` +instructionRemainingAccountsNode(argumentValueNode('authorities'), { + isSigner: 'either', +}); +`, + ), + ), + example( + 'Remaining accounts using a resolver', + code( + 'typescript', + ` +instructionRemainingAccountsNode( + resolverValueNode('resolveTransferRemainingAccounts', { + docs: ['Provide authorities as remaining accounts if and only if the asset has a multisig set up.'], + dependsOn: [argumentValueNode('hasMultisig'), argumentValueNode('authorities')], + }), +); +`, + ), + ), +]; diff --git a/src/v1/nodes/InstructionRemainingAccountsNode.ts b/src/v1/nodes/InstructionRemainingAccountsNode.ts index e3c6392b..fbb281c8 100644 --- a/src/v1/nodes/InstructionRemainingAccountsNode.ts +++ b/src/v1/nodes/InstructionRemainingAccountsNode.ts @@ -1,4 +1,5 @@ import { attribute, boolean, defineNode, docs, literalUnion, node, optionalAttribute, union } from '../../api'; +import { examples } from './InstructionRemainingAccountsNode.examples'; export const instructionRemainingAccountsNode = defineNode('instructionRemainingAccountsNode', { docs: ['A "remaining accounts" slot in an instruction — a variable-length tail of accounts derived from a value.'], @@ -25,4 +26,5 @@ export const instructionRemainingAccountsNode = defineNode('instructionRemaining docs: ['Display metadata describing how the remaining-accounts group is presented as a whole.'], }), ], + examples, }); diff --git a/src/v1/nodes/InstructionStatusNode.examples.ts b/src/v1/nodes/InstructionStatusNode.examples.ts new file mode 100644 index 00000000..64223c7d --- /dev/null +++ b/src/v1/nodes/InstructionStatusNode.examples.ts @@ -0,0 +1,73 @@ +import { code, example, type DocExamples } from '../../api'; + +export const examples: DocExamples = [ + example( + 'A live instruction (no status needed)', + code( + 'typescript', + ` +instructionNode({ + name: 'transfer', + accounts: [...], + arguments: [...], +}); +`, + ), + ), + example( + 'A deprecated instruction', + code( + 'typescript', + ` +instructionNode({ + name: 'oldTransfer', + status: instructionStatusNode('deprecated', 'Use the \`transfer\` instruction instead. This will be removed in v3.0.0.'), + accounts: [...], + arguments: [...], +}); +`, + ), + ), + example( + 'An archived instruction', + code( + 'typescript', + ` +instructionNode({ + name: 'legacyTransfer', + status: instructionStatusNode('archived', 'This instruction was removed in v2.0.0. It is kept here for historical parsing.'), + accounts: [...], + arguments: [...], +}); +`, + ), + ), + example( + 'A draft instruction', + code( + 'typescript', + ` +instructionNode({ + name: 'experimentalFeature', + status: instructionStatusNode('draft', 'This instruction is under development and may change.'), + accounts: [...], + arguments: [...], +}); +`, + ), + ), + example( + 'Status without a message', + code( + 'typescript', + ` +instructionNode({ + name: 'someInstruction', + status: instructionStatusNode('deprecated'), + accounts: [...], + arguments: [...], +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/InstructionStatusNode.ts b/src/v1/nodes/InstructionStatusNode.ts index 26988f11..9b9b9c96 100644 --- a/src/v1/nodes/InstructionStatusNode.ts +++ b/src/v1/nodes/InstructionStatusNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, enumeration, optionalAttribute, string } from '../../api'; +import { examples } from './InstructionStatusNode.examples'; export const instructionStatusNode = defineNode('instructionStatusNode', { docs: [ @@ -12,4 +13,5 @@ export const instructionStatusNode = defineNode('instructionStatusNode', { docs: ['Free-form prose accompanying the status — e.g. a deprecation notice with migration guidance.'], }), ], + examples, }); diff --git a/src/v1/nodes/PdaNode.examples.ts b/src/v1/nodes/PdaNode.examples.ts new file mode 100644 index 00000000..ab0542ed --- /dev/null +++ b/src/v1/nodes/PdaNode.examples.ts @@ -0,0 +1,33 @@ +import { code, example, type DocExamples } from '../../api'; + +export const examples: DocExamples = [ + example( + 'A PDA with constant and variable seeds', + code( + 'typescript', + ` +pdaNode({ + name: 'ticket', + seeds: [ + constantPdaSeedNodeFromString('utf8', 'raffles'), + variablePdaSeedNode('raffle', publicKeyTypeNode()), + constantPdaSeedNodeFromString('utf8', 'tickets'), + variablePdaSeedNode('ticketNumber', numberTypeNode('u32')), + ], +}); +`, + ), + ), + example( + 'A PDA with no seeds', + code( + 'typescript', + ` +pdaNode({ + name: 'seedlessPda', + seeds: [], +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/PdaNode.ts b/src/v1/nodes/PdaNode.ts index 130640b9..125394b2 100644 --- a/src/v1/nodes/PdaNode.ts +++ b/src/v1/nodes/PdaNode.ts @@ -1,4 +1,5 @@ import { address, array, attribute, defineNode, docs, optionalAttribute, stringIdentifier, union } from '../../api'; +import { examples } from './PdaNode.examples'; export const pdaNode = defineNode('pdaNode', { docs: ['A program-derived address: its name, optional program ID override, and the seeds used to derive it.'], @@ -18,4 +19,5 @@ export const pdaNode = defineNode('pdaNode', { docs: ['The seeds used to derive the PDA, in order.'], }), ], + examples, }); diff --git a/src/v1/nodes/ProgramNode.examples.ts b/src/v1/nodes/ProgramNode.examples.ts new file mode 100644 index 00000000..fff7ccd8 --- /dev/null +++ b/src/v1/nodes/ProgramNode.examples.ts @@ -0,0 +1,23 @@ +import { code, example, type DocExamples } from '../../api'; + +export const examples: DocExamples = [ + example( + 'Create a program node from an input object', + code( + 'typescript', + ` +const node = programNode({ + name: 'counter', + publicKey: '7ovtg4pFqjQdSwFAUCu8gTnh5thZHzAyJFXy3Ssnj3yK', + version: '1.42.6', + accounts: [], + instructions: [], + definedTypes: [], + pdas: [], + events: [], + errors: [], +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/ProgramNode.ts b/src/v1/nodes/ProgramNode.ts index 9059f715..d0a9d83f 100644 --- a/src/v1/nodes/ProgramNode.ts +++ b/src/v1/nodes/ProgramNode.ts @@ -10,6 +10,7 @@ import { stringIdentifier, stringVersion, } from '../../api'; +import { examples } from './ProgramNode.examples'; export const programNode = defineNode('programNode', { docs: [ @@ -53,4 +54,5 @@ export const programNode = defineNode('programNode', { docs: ['The constants exposed by the program.'], }), ], + examples, }); diff --git a/src/v1/nodes/RootNode.examples.ts b/src/v1/nodes/RootNode.examples.ts new file mode 100644 index 00000000..3ff2c855 --- /dev/null +++ b/src/v1/nodes/RootNode.examples.ts @@ -0,0 +1,34 @@ +import { code, example, type DocExamples } from '../../api'; + +export const examples: DocExamples = [ + example( + 'A root node with a single program', + code( + 'typescript', + ` +const node = rootNode( + programNode({ + name: 'counter', + publicKey: '2R3Ui2TVUUCyGcZdopxJauk8ZBzgAaHHZCVUhm5ifPaC', + version: '1.0.0', + accounts: [ + accountNode({ + name: 'counter', + data: structTypeNode([ + structFieldTypeNode({ name: 'authority', type: publicKeyTypeNode() }), + structFieldTypeNode({ name: 'value', type: numberTypeNode('u32') }), + ]), + }), + ], + instructions: [ + instructionNode({ name: 'create' /* ... */ }), + instructionNode({ name: 'increment' /* ... */ }), + instructionNode({ name: 'transferAuthority' /* ... */ }), + instructionNode({ name: 'delete' /* ... */ }), + ], + }), +); +`, + ), + ), +]; diff --git a/src/v1/nodes/RootNode.ts b/src/v1/nodes/RootNode.ts index 3d271254..8285ab2a 100644 --- a/src/v1/nodes/RootNode.ts +++ b/src/v1/nodes/RootNode.ts @@ -1,4 +1,5 @@ import { array, attribute, codamaVersion, defineNode, literal, node } from '../../api'; +import { examples } from './RootNode.examples'; export const rootNode = defineNode('rootNode', { docs: [ @@ -19,4 +20,5 @@ export const rootNode = defineNode('rootNode', { docs: ['Additional programs referenced by the primary program.'], }), ], + examples, }); diff --git a/src/v1/nodes/contextualValueNodes/AccountBumpValueNode.examples.ts b/src/v1/nodes/contextualValueNodes/AccountBumpValueNode.examples.ts new file mode 100644 index 00000000..ec1f37d9 --- /dev/null +++ b/src/v1/nodes/contextualValueNodes/AccountBumpValueNode.examples.ts @@ -0,0 +1,40 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create an account bump value node from an account name', + code( + 'typescript', + ` +const node = accountBumpValueNode('associatedTokenAccount'); +`, + ), + ), + example( + 'An instruction argument defaulting to the bump derivation of an instruction account', + code( + 'typescript', + ` +instructionNode({ + name: 'transfer', + accounts: [ + instructionAccountNode({ + name: 'associatedTokenAccount', + isSigner: false, + isWritable: true, + }), + // ... + ], + arguments: [ + instructionArgumentNode({ + name: 'bump', + type: numberTypeNode('u8'), + defaultValue: accountBumpValueNode('associatedTokenAccount'), + }), + // ... + ], +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/contextualValueNodes/AccountBumpValueNode.ts b/src/v1/nodes/contextualValueNodes/AccountBumpValueNode.ts index 5c6553f6..fff0b5fd 100644 --- a/src/v1/nodes/contextualValueNodes/AccountBumpValueNode.ts +++ b/src/v1/nodes/contextualValueNodes/AccountBumpValueNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, stringIdentifier } from '../../../api'; +import { examples } from './AccountBumpValueNode.examples'; export const accountBumpValueNode = defineNode('accountBumpValueNode', { docs: ['Refers to the bump seed of a named PDA-derived account in the surrounding instruction.'], @@ -7,4 +8,5 @@ export const accountBumpValueNode = defineNode('accountBumpValueNode', { docs: ['The name of the account whose bump seed is referenced.'], }), ], + examples, }); diff --git a/src/v1/nodes/contextualValueNodes/AccountValueNode.examples.ts b/src/v1/nodes/contextualValueNodes/AccountValueNode.examples.ts new file mode 100644 index 00000000..b3af9273 --- /dev/null +++ b/src/v1/nodes/contextualValueNodes/AccountValueNode.examples.ts @@ -0,0 +1,38 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create an account value node from an account name', + code( + 'typescript', + ` +const node = accountValueNode('mint'); +`, + ), + ), + example( + 'An instruction account defaulting to another account', + code( + 'typescript', + ` +instructionNode({ + name: 'mint', + accounts: [ + instructionAccountNode({ + name: 'payer', + isSigner: true, + isWritable: false, + }), + instructionAccountNode({ + name: 'authority', + isSigner: false, + isWritable: true, + defaultValue: accountValueNode('payer'), + }), + // ... + ], +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/contextualValueNodes/AccountValueNode.ts b/src/v1/nodes/contextualValueNodes/AccountValueNode.ts index 331fa5fe..0eed480b 100644 --- a/src/v1/nodes/contextualValueNodes/AccountValueNode.ts +++ b/src/v1/nodes/contextualValueNodes/AccountValueNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, stringIdentifier } from '../../../api'; +import { examples } from './AccountValueNode.examples'; export const accountValueNode = defineNode('accountValueNode', { docs: ['Refers to a named account in the surrounding instruction.'], @@ -7,4 +8,5 @@ export const accountValueNode = defineNode('accountValueNode', { docs: ['The name of the referenced account.'], }), ], + examples, }); diff --git a/src/v1/nodes/contextualValueNodes/ArgumentValueNode.examples.ts b/src/v1/nodes/contextualValueNodes/ArgumentValueNode.examples.ts new file mode 100644 index 00000000..83e0bca8 --- /dev/null +++ b/src/v1/nodes/contextualValueNodes/ArgumentValueNode.examples.ts @@ -0,0 +1,36 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create an argument value node from an argument name', + code( + 'typescript', + ` +const node = argumentValueNode('amount'); +`, + ), + ), + example( + 'An instruction argument defaulting to another argument', + code( + 'typescript', + ` +instructionNode({ + name: 'mint', + arguments: [ + instructionArgumentNode({ + name: 'amount', + type: numberTypeNode('u64'), + }), + instructionArgumentNode({ + name: 'amountToDelegate', + type: numberTypeNode('u64'), + defaultValue: argumentValueNode('amount'), + }), + // ... + ], +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/contextualValueNodes/ArgumentValueNode.ts b/src/v1/nodes/contextualValueNodes/ArgumentValueNode.ts index d4290929..d5b70507 100644 --- a/src/v1/nodes/contextualValueNodes/ArgumentValueNode.ts +++ b/src/v1/nodes/contextualValueNodes/ArgumentValueNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, stringIdentifier } from '../../../api'; +import { examples } from './ArgumentValueNode.examples'; export const argumentValueNode = defineNode('argumentValueNode', { docs: ['Refers to a named argument of the surrounding instruction.'], @@ -7,4 +8,5 @@ export const argumentValueNode = defineNode('argumentValueNode', { docs: ['The name of the referenced argument.'], }), ], + examples, }); diff --git a/src/v1/nodes/contextualValueNodes/ConditionalValueNode.examples.ts b/src/v1/nodes/contextualValueNodes/ConditionalValueNode.examples.ts new file mode 100644 index 00000000..8c0e688a --- /dev/null +++ b/src/v1/nodes/contextualValueNodes/ConditionalValueNode.examples.ts @@ -0,0 +1,54 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a conditional value node from an input object', + code( + 'typescript', + ` +const node = conditionalValueNode({ + condition: argumentValueNode('amount'), + value: numberValueNode(0), + ifTrue: accountValueNode('mint'), + ifFalse: programIdValueNode(), +}); +`, + ), + ), + example( + 'An instruction account that defaults to another account if a condition is met', + code( + 'typescript', + ` +instructionNode({ + name: 'transfer', + accounts: [ + instructionAccountNode({ + name: 'source', + isSigner: false, + isWritable: true, + }), + instructionAccountNode({ + name: 'destination', + isSigner: false, + isWritable: true, + isOptional: true, + defaultValue: conditionalValueNode({ + condition: argumentValueNode('amount'), + value: numberValueNode(0), + ifTrue: accountValueNode('source'), + }), + }), + // ... + ], + arguments: [ + instructionArgumentNode({ + name: 'amount', + type: numberTypeNode('u64'), + }), + ], +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/contextualValueNodes/ConditionalValueNode.ts b/src/v1/nodes/contextualValueNodes/ConditionalValueNode.ts index 4e6f3d3e..0fd98fd5 100644 --- a/src/v1/nodes/contextualValueNodes/ConditionalValueNode.ts +++ b/src/v1/nodes/contextualValueNodes/ConditionalValueNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, optionalAttribute, union } from '../../../api'; +import { examples } from './ConditionalValueNode.examples'; export const conditionalValueNode = defineNode('conditionalValueNode', { docs: [ @@ -22,4 +23,5 @@ export const conditionalValueNode = defineNode('conditionalValueNode', { docs: ['The value used when the condition resolves falsy (or does not match `value`).'], }), ], + examples, }); diff --git a/src/v1/nodes/contextualValueNodes/IdentityValueNode.examples.ts b/src/v1/nodes/contextualValueNodes/IdentityValueNode.examples.ts new file mode 100644 index 00000000..e386bc03 --- /dev/null +++ b/src/v1/nodes/contextualValueNodes/IdentityValueNode.examples.ts @@ -0,0 +1,33 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create an identity value node', + code( + 'typescript', + ` +const node = identityValueNode(); +`, + ), + ), + example( + 'An instruction account defaulting to the identity value', + code( + 'typescript', + ` +instructionNode({ + name: 'transfer', + accounts: [ + instructionAccountNode({ + name: 'authority', + isSigner: true, + isWritable: false, + defaultValue: identityValueNode(), + }), + // ... + ], +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/contextualValueNodes/IdentityValueNode.ts b/src/v1/nodes/contextualValueNodes/IdentityValueNode.ts index 376661fb..26d70394 100644 --- a/src/v1/nodes/contextualValueNodes/IdentityValueNode.ts +++ b/src/v1/nodes/contextualValueNodes/IdentityValueNode.ts @@ -1,6 +1,8 @@ import { defineNode } from '../../../api'; +import { examples } from './IdentityValueNode.examples'; export const identityValueNode = defineNode('identityValueNode', { docs: ['Refers to the wallet identity providing the instruction context.'], attributes: [], + examples, }); diff --git a/src/v1/nodes/contextualValueNodes/PayerValueNode.examples.ts b/src/v1/nodes/contextualValueNodes/PayerValueNode.examples.ts new file mode 100644 index 00000000..db6cf8ae --- /dev/null +++ b/src/v1/nodes/contextualValueNodes/PayerValueNode.examples.ts @@ -0,0 +1,33 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a payer value node', + code( + 'typescript', + ` +const node = payerValueNode(); +`, + ), + ), + example( + 'An instruction account defaulting to the payer value', + code( + 'typescript', + ` +instructionNode({ + name: 'transfer', + accounts: [ + instructionAccountNode({ + name: 'payer', + isSigner: true, + isWritable: false, + defaultValue: payerValueNode(), + }), + // ... + ], +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/contextualValueNodes/PayerValueNode.ts b/src/v1/nodes/contextualValueNodes/PayerValueNode.ts index 9d29a85a..cdf37da8 100644 --- a/src/v1/nodes/contextualValueNodes/PayerValueNode.ts +++ b/src/v1/nodes/contextualValueNodes/PayerValueNode.ts @@ -1,6 +1,8 @@ import { defineNode } from '../../../api'; +import { examples } from './PayerValueNode.examples'; export const payerValueNode = defineNode('payerValueNode', { docs: ['Refers to the wallet paying for the surrounding transaction.'], attributes: [], + examples, }); diff --git a/src/v1/nodes/contextualValueNodes/PdaSeedValueNode.examples.ts b/src/v1/nodes/contextualValueNodes/PdaSeedValueNode.examples.ts new file mode 100644 index 00000000..e805b86a --- /dev/null +++ b/src/v1/nodes/contextualValueNodes/PdaSeedValueNode.examples.ts @@ -0,0 +1,13 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a PDA seed value node from a name and a value', + code( + 'typescript', + ` +const node = pdaSeedValueNode('mint', accountValueNode('mint')); +`, + ), + ), +]; diff --git a/src/v1/nodes/contextualValueNodes/PdaSeedValueNode.ts b/src/v1/nodes/contextualValueNodes/PdaSeedValueNode.ts index a7450003..43eea952 100644 --- a/src/v1/nodes/contextualValueNodes/PdaSeedValueNode.ts +++ b/src/v1/nodes/contextualValueNodes/PdaSeedValueNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, stringIdentifier, union } from '../../../api'; +import { examples } from './PdaSeedValueNode.examples'; export const pdaSeedValueNode = defineNode('pdaSeedValueNode', { docs: ['Pairs a PDA seed name with the value to substitute when deriving the PDA.'], @@ -10,4 +11,5 @@ export const pdaSeedValueNode = defineNode('pdaSeedValueNode', { docs: ['The value to substitute for the seed.'], }), ], + examples, }); diff --git a/src/v1/nodes/contextualValueNodes/PdaValueNode.examples.ts b/src/v1/nodes/contextualValueNodes/PdaValueNode.examples.ts new file mode 100644 index 00000000..a14f5ed7 --- /dev/null +++ b/src/v1/nodes/contextualValueNodes/PdaValueNode.examples.ts @@ -0,0 +1,49 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a PDA value node from a PDA definition and seed values', + code( + 'typescript', + ` +const node = pdaValueNode('associatedToken', [ + pdaSeedValueNode('mint', publicKeyValueNode('G345gmp34svbGxyXuCvKVVHDbqJQ66y65vVrx7m7FmBE')), + pdaSeedValueNode('owner', publicKeyValueNode('Nzgr9bYfMRq5768bHfXsXoPTnLWAXgQNosRBxK63jRH')), +]); +`, + ), + ), + example( + 'A PDA value whose seeds point to other accounts', + code( + 'typescript', + ` +pdaValueNode('associatedToken', [ + pdaSeedValueNode('mint', accountValueNode('mint')), + pdaSeedValueNode('owner', accountValueNode('authority')), +]); +`, + ), + ), + example( + 'A PDA value with an inlined PDA definition', + code( + 'typescript', + ` +const inlinedPdaNode = pdaNode({ + name: 'associatedToken', + seeds: [ + variablePdaSeedNode('mint', publicKeyTypeNode()), + constantPdaSeedNode(publicKeyTypeNode(), publicKeyValueNode('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA')), + variablePdaSeedNode('owner', publicKeyTypeNode()), + ], +}); + +pdaValueNode(inlinedPdaNode, [ + pdaSeedValueNode('mint', accountValueNode('mint')), + pdaSeedValueNode('owner', accountValueNode('authority')), +]); +`, + ), + ), +]; diff --git a/src/v1/nodes/contextualValueNodes/PdaValueNode.ts b/src/v1/nodes/contextualValueNodes/PdaValueNode.ts index 4ff22d3a..97110104 100644 --- a/src/v1/nodes/contextualValueNodes/PdaValueNode.ts +++ b/src/v1/nodes/contextualValueNodes/PdaValueNode.ts @@ -1,4 +1,5 @@ import { array, attribute, defineNode, node, optionalAttribute, union } from '../../../api'; +import { examples } from './PdaValueNode.examples'; export const pdaValueNode = defineNode('pdaValueNode', { docs: ['Resolves to a PDA derived from a list of seed values.'], @@ -13,4 +14,5 @@ export const pdaValueNode = defineNode('pdaValueNode', { docs: ['The program ID used to derive the PDA. When omitted, the PDA\u2019s declared program is used.'], }), ], + examples, }); diff --git a/src/v1/nodes/contextualValueNodes/ProgramIdValueNode.examples.ts b/src/v1/nodes/contextualValueNodes/ProgramIdValueNode.examples.ts new file mode 100644 index 00000000..6b7c99ef --- /dev/null +++ b/src/v1/nodes/contextualValueNodes/ProgramIdValueNode.examples.ts @@ -0,0 +1,13 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a program id value node', + code( + 'typescript', + ` +const node = programIdValueNode(); +`, + ), + ), +]; diff --git a/src/v1/nodes/contextualValueNodes/ProgramIdValueNode.ts b/src/v1/nodes/contextualValueNodes/ProgramIdValueNode.ts index 71c53ff9..2c99e854 100644 --- a/src/v1/nodes/contextualValueNodes/ProgramIdValueNode.ts +++ b/src/v1/nodes/contextualValueNodes/ProgramIdValueNode.ts @@ -1,6 +1,8 @@ import { defineNode } from '../../../api'; +import { examples } from './ProgramIdValueNode.examples'; export const programIdValueNode = defineNode('programIdValueNode', { docs: ['Refers to the program ID of the surrounding instruction.'], attributes: [], + examples, }); diff --git a/src/v1/nodes/contextualValueNodes/ResolverValueNode.examples.ts b/src/v1/nodes/contextualValueNodes/ResolverValueNode.examples.ts new file mode 100644 index 00000000..d45742c4 --- /dev/null +++ b/src/v1/nodes/contextualValueNodes/ResolverValueNode.examples.ts @@ -0,0 +1,20 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a resolver value node from a name and options', + code( + 'typescript', + ` +const node = resolverValueNode('resolveCustomTokenProgram', { + docs: [ + 'If the mint account has more than 0 decimals and the ', + 'delegated amount is greater than zero, then we use our ', + 'own custom token program. Otherwise, we use Token 2022.', + ], + dependsOn: [accountValueNode('mint'), argumentValueNode('delegatedAmount')], +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/contextualValueNodes/ResolverValueNode.ts b/src/v1/nodes/contextualValueNodes/ResolverValueNode.ts index 013bcf0b..77a90388 100644 --- a/src/v1/nodes/contextualValueNodes/ResolverValueNode.ts +++ b/src/v1/nodes/contextualValueNodes/ResolverValueNode.ts @@ -1,4 +1,5 @@ import { array, attribute, defineNode, docs, optionalAttribute, stringIdentifier, union } from '../../../api'; +import { examples } from './ResolverValueNode.examples'; export const resolverValueNode = defineNode('resolverValueNode', { docs: [ @@ -18,4 +19,5 @@ export const resolverValueNode = defineNode('resolverValueNode', { ], }), ], + examples, }); diff --git a/src/v1/nodes/countNodes/FixedCountNode.examples.ts b/src/v1/nodes/countNodes/FixedCountNode.examples.ts new file mode 100644 index 00000000..d7bb1d98 --- /dev/null +++ b/src/v1/nodes/countNodes/FixedCountNode.examples.ts @@ -0,0 +1,22 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a fixed count node from a number', + code( + 'typescript', + ` +const node = fixedCountNode(42); +`, + ), + ), + example( + 'An array of three public keys', + code( + 'typescript', + ` +arrayTypeNode(publicKeyTypeNode(), fixedCountNode(3)); +`, + ), + ), +]; diff --git a/src/v1/nodes/countNodes/FixedCountNode.ts b/src/v1/nodes/countNodes/FixedCountNode.ts index 4884e436..0b6488f5 100644 --- a/src/v1/nodes/countNodes/FixedCountNode.ts +++ b/src/v1/nodes/countNodes/FixedCountNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, u64 } from '../../../api'; +import { examples } from './FixedCountNode.examples'; export const fixedCountNode = defineNode('fixedCountNode', { docs: ['A count strategy that fixes the number of items at a constant value.'], @@ -7,4 +8,5 @@ export const fixedCountNode = defineNode('fixedCountNode', { docs: ['The fixed number of items.'], }), ], + examples, }); diff --git a/src/v1/nodes/countNodes/PrefixedCountNode.examples.ts b/src/v1/nodes/countNodes/PrefixedCountNode.examples.ts new file mode 100644 index 00000000..75cb284b --- /dev/null +++ b/src/v1/nodes/countNodes/PrefixedCountNode.examples.ts @@ -0,0 +1,22 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a prefixed count node from a number node', + code( + 'typescript', + ` +const node = prefixedCountNode(numberTypeNode('u32')); +`, + ), + ), + example( + 'A variable array of public keys prefixed with a u32', + code( + 'typescript', + ` +arrayTypeNode(publicKeyTypeNode(), prefixedCountNode(numberTypeNode('u32'))); +`, + ), + ), +]; diff --git a/src/v1/nodes/countNodes/PrefixedCountNode.ts b/src/v1/nodes/countNodes/PrefixedCountNode.ts index e4ab73ec..c174c57d 100644 --- a/src/v1/nodes/countNodes/PrefixedCountNode.ts +++ b/src/v1/nodes/countNodes/PrefixedCountNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, nestedUnion } from '../../../api'; +import { examples } from './PrefixedCountNode.examples'; export const prefixedCountNode = defineNode('prefixedCountNode', { docs: ['A count strategy where the number of items is read from a numeric prefix.'], @@ -7,4 +8,5 @@ export const prefixedCountNode = defineNode('prefixedCountNode', { docs: ['The numeric type used as the count prefix.'], }), ], + examples, }); diff --git a/src/v1/nodes/countNodes/RemainderCountNode.examples.ts b/src/v1/nodes/countNodes/RemainderCountNode.examples.ts new file mode 100644 index 00000000..2fd7f37f --- /dev/null +++ b/src/v1/nodes/countNodes/RemainderCountNode.examples.ts @@ -0,0 +1,22 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a remainder count node', + code( + 'typescript', + ` +const node = remainderCountNode(); +`, + ), + ), + example( + 'A remainder array of public keys', + code( + 'typescript', + ` +arrayTypeNode(publicKeyTypeNode(), remainderCountNode()); +`, + ), + ), +]; diff --git a/src/v1/nodes/countNodes/RemainderCountNode.ts b/src/v1/nodes/countNodes/RemainderCountNode.ts index 840541d8..45ad688b 100644 --- a/src/v1/nodes/countNodes/RemainderCountNode.ts +++ b/src/v1/nodes/countNodes/RemainderCountNode.ts @@ -1,6 +1,8 @@ import { defineNode } from '../../../api'; +import { examples } from './RemainderCountNode.examples'; export const remainderCountNode = defineNode('remainderCountNode', { docs: ['A count strategy where items are read until the buffer is exhausted.'], attributes: [], + examples, }); diff --git a/src/v1/nodes/discriminatorNodes/ConstantDiscriminatorNode.examples.ts b/src/v1/nodes/discriminatorNodes/ConstantDiscriminatorNode.examples.ts new file mode 100644 index 00000000..919d6193 --- /dev/null +++ b/src/v1/nodes/discriminatorNodes/ConstantDiscriminatorNode.examples.ts @@ -0,0 +1,39 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a constant discriminator node from a constant value and an optional offset', + code( + 'typescript', + ` +const node = constantDiscriminatorNode(constantValueNode(stringTypeNode('utf8'), stringValueNode('Hello')), 64); +`, + ), + ), + example( + 'An account distinguished by a u32 number equal to 42 at offset 0', + code( + 'typescript', + ` +accountNode({ + discriminators: [constantDiscriminatorNode(constantValueNode(numberTypeNode('u32'), numberValueNode(42)))], + // ... +}); +`, + ), + ), + example( + 'An instruction distinguished by an 8-byte hash at offset 0', + code( + 'typescript', + ` +instructionNode({ + discriminators: [ + constantDiscriminatorNode(constantValueNode(bytesTypeNode(), bytesValueNode('base16', '0011223344556677'))), + ], + // ... +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/discriminatorNodes/ConstantDiscriminatorNode.ts b/src/v1/nodes/discriminatorNodes/ConstantDiscriminatorNode.ts index bb238b82..58e926a5 100644 --- a/src/v1/nodes/discriminatorNodes/ConstantDiscriminatorNode.ts +++ b/src/v1/nodes/discriminatorNodes/ConstantDiscriminatorNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, node, u64 } from '../../../api'; +import { examples } from './ConstantDiscriminatorNode.examples'; export const constantDiscriminatorNode = defineNode('constantDiscriminatorNode', { docs: ['Identifies a node by a constant value at a known byte offset (e.g. a magic header).'], @@ -10,4 +11,5 @@ export const constantDiscriminatorNode = defineNode('constantDiscriminatorNode', docs: ['The constant value expected at the offset.'], }), ], + examples, }); diff --git a/src/v1/nodes/discriminatorNodes/FieldDiscriminatorNode.examples.ts b/src/v1/nodes/discriminatorNodes/FieldDiscriminatorNode.examples.ts new file mode 100644 index 00000000..4f618b22 --- /dev/null +++ b/src/v1/nodes/discriminatorNodes/FieldDiscriminatorNode.examples.ts @@ -0,0 +1,55 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a field discriminator node from a field name and an optional offset', + code( + 'typescript', + ` +const node = fieldDiscriminatorNode('accountState', 64); +`, + ), + ), + example( + 'An account distinguished by a u32 field at offset 0', + code( + 'typescript', + ` +accountNode({ + data: structTypeNode([ + structFieldTypeNode({ + name: 'discriminator', + type: numberTypeNode('u32'), + defaultValue: numberValueNode(42), + defaultValueStrategy: 'omitted', + }), + // ... + ]), + discriminators: [fieldDiscriminatorNode('discriminator')], + // ... +}); +`, + ), + ), + example( + 'An instruction distinguished by an 8-byte argument at offset 0', + code( + 'typescript', + ` +instructionNode({ + arguments: [ + instructionArgumentNode({ + name: 'discriminator', + type: fixedSizeTypeNode(bytesTypeNode(), 8), + defaultValue: bytesValueNode('base16', '0011223344556677'), + defaultValueStrategy: 'omitted', + }), + // ... + ], + discriminators: [fieldDiscriminatorNode('discriminator')], + // ... +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/discriminatorNodes/FieldDiscriminatorNode.ts b/src/v1/nodes/discriminatorNodes/FieldDiscriminatorNode.ts index 294bd072..e27a9042 100644 --- a/src/v1/nodes/discriminatorNodes/FieldDiscriminatorNode.ts +++ b/src/v1/nodes/discriminatorNodes/FieldDiscriminatorNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, stringIdentifier, u64 } from '../../../api'; +import { examples } from './FieldDiscriminatorNode.examples'; export const fieldDiscriminatorNode = defineNode('fieldDiscriminatorNode', { docs: ['Identifies a node by the value of a named field at a known byte offset.'], @@ -10,4 +11,5 @@ export const fieldDiscriminatorNode = defineNode('fieldDiscriminatorNode', { docs: ['The byte offset of the field.'], }), ], + examples, }); diff --git a/src/v1/nodes/discriminatorNodes/SizeDiscriminatorNode.examples.ts b/src/v1/nodes/discriminatorNodes/SizeDiscriminatorNode.examples.ts new file mode 100644 index 00000000..88932495 --- /dev/null +++ b/src/v1/nodes/discriminatorNodes/SizeDiscriminatorNode.examples.ts @@ -0,0 +1,37 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a size discriminator node from a size', + code( + 'typescript', + ` +const node = sizeDiscriminatorNode(165); +`, + ), + ), + example( + 'An account distinguished by its size being equal to 42', + code( + 'typescript', + ` +accountNode({ + discriminators: [sizeDiscriminatorNode(42)], + // ... +}); +`, + ), + ), + example( + 'An instruction distinguished by its size being equal to 42', + code( + 'typescript', + ` +instructionNode({ + discriminators: [sizeDiscriminatorNode(42)], + // ... +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/discriminatorNodes/SizeDiscriminatorNode.ts b/src/v1/nodes/discriminatorNodes/SizeDiscriminatorNode.ts index 9727977e..ae012fcb 100644 --- a/src/v1/nodes/discriminatorNodes/SizeDiscriminatorNode.ts +++ b/src/v1/nodes/discriminatorNodes/SizeDiscriminatorNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, u64 } from '../../../api'; +import { examples } from './SizeDiscriminatorNode.examples'; export const sizeDiscriminatorNode = defineNode('sizeDiscriminatorNode', { docs: ['Identifies a node by its expected total byte size.'], @@ -7,4 +8,5 @@ export const sizeDiscriminatorNode = defineNode('sizeDiscriminatorNode', { docs: ['The expected byte size.'], }), ], + examples, }); diff --git a/src/v1/nodes/displayNodes/AmountNumberDisplayNode.examples.ts b/src/v1/nodes/displayNodes/AmountNumberDisplayNode.examples.ts new file mode 100644 index 00000000..09846474 --- /dev/null +++ b/src/v1/nodes/displayNodes/AmountNumberDisplayNode.examples.ts @@ -0,0 +1,33 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'A fixed 9-decimal SOL amount', + code( + 'typescript', + ` +numberTypeNode('u64', 'le', { + display: amountNumberDisplayNode({ decimals: numberValueNode(9), unit: stringValueNode('SOL') }), +}); + +// 1_100_000_000 => "1.1 SOL" +`, + ), + ), + example( + 'Decimals and unit injected from surrounding account state', + code( + 'typescript', + ` +numberTypeNode('u64', 'le', { + display: amountNumberDisplayNode({ + decimals: injectedValueNode({ key: 'decimals' }), + unit: injectedValueNode({ key: 'symbol' }), + }), +}); + +// 1_500_000 with injected decimals 6 and symbol "USDC" => "1.5 USDC" +`, + ), + ), +]; diff --git a/src/v1/nodes/displayNodes/AmountNumberDisplayNode.ts b/src/v1/nodes/displayNodes/AmountNumberDisplayNode.ts index a97de62c..f21d9900 100644 --- a/src/v1/nodes/displayNodes/AmountNumberDisplayNode.ts +++ b/src/v1/nodes/displayNodes/AmountNumberDisplayNode.ts @@ -1,4 +1,5 @@ import { defineNode, optionalAttribute, union } from '../../../api'; +import { examples } from './AmountNumberDisplayNode.examples'; export const amountNumberDisplayNode = defineNode('amountNumberDisplayNode', { docs: [ @@ -20,4 +21,5 @@ export const amountNumberDisplayNode = defineNode('amountNumberDisplayNode', { ], }), ], + examples, }); diff --git a/src/v1/nodes/displayNodes/DateTimeNumberDisplayNode.examples.ts b/src/v1/nodes/displayNodes/DateTimeNumberDisplayNode.examples.ts new file mode 100644 index 00000000..0c77072f --- /dev/null +++ b/src/v1/nodes/displayNodes/DateTimeNumberDisplayNode.examples.ts @@ -0,0 +1,26 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'A Unix timestamp already in seconds', + code( + 'typescript', + ` +numberTypeNode('i64', 'le', { display: dateTimeNumberDisplayNode({}) }); + +// 1_761_365_183 => "2025-10-25T04:06:23.000Z" +`, + ), + ), + example( + 'A millisecond timestamp scaled back to seconds', + code( + 'typescript', + ` +numberTypeNode('i64', 'le', { display: dateTimeNumberDisplayNode({ ticksPerSecond: 1000 }) }); + +// 1_761_365_183_000 => "2025-10-25T04:06:23.000Z" +`, + ), + ), +]; diff --git a/src/v1/nodes/displayNodes/DateTimeNumberDisplayNode.ts b/src/v1/nodes/displayNodes/DateTimeNumberDisplayNode.ts index 4cdc8fe6..34c94452 100644 --- a/src/v1/nodes/displayNodes/DateTimeNumberDisplayNode.ts +++ b/src/v1/nodes/displayNodes/DateTimeNumberDisplayNode.ts @@ -1,4 +1,5 @@ import { defineNode, optionalAttribute, u64 } from '../../../api'; +import { examples } from './DateTimeNumberDisplayNode.examples'; export const dateTimeNumberDisplayNode = defineNode('dateTimeNumberDisplayNode', { docs: [ @@ -13,4 +14,5 @@ export const dateTimeNumberDisplayNode = defineNode('dateTimeNumberDisplayNode', ], }), ], + examples, }); diff --git a/src/v1/nodes/displayNodes/DurationNumberDisplayNode.examples.ts b/src/v1/nodes/displayNodes/DurationNumberDisplayNode.examples.ts new file mode 100644 index 00000000..73428905 --- /dev/null +++ b/src/v1/nodes/displayNodes/DurationNumberDisplayNode.examples.ts @@ -0,0 +1,26 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'A duration already in seconds', + code( + 'typescript', + ` +numberTypeNode('u32', 'le', { display: durationNumberDisplayNode({}) }); + +// 3600 => "01:00:00" +`, + ), + ), + example( + 'A duration in milliseconds scaled back to seconds', + code( + 'typescript', + ` +numberTypeNode('u64', 'le', { display: durationNumberDisplayNode({ ticksPerSecond: 1000 }) }); + +// 90_000 => "00:01:30" +`, + ), + ), +]; diff --git a/src/v1/nodes/displayNodes/DurationNumberDisplayNode.ts b/src/v1/nodes/displayNodes/DurationNumberDisplayNode.ts index acf7ae11..7826cff2 100644 --- a/src/v1/nodes/displayNodes/DurationNumberDisplayNode.ts +++ b/src/v1/nodes/displayNodes/DurationNumberDisplayNode.ts @@ -1,4 +1,5 @@ import { defineNode, optionalAttribute, u64 } from '../../../api'; +import { examples } from './DurationNumberDisplayNode.examples'; export const durationNumberDisplayNode = defineNode('durationNumberDisplayNode', { docs: [ @@ -14,4 +15,5 @@ export const durationNumberDisplayNode = defineNode('durationNumberDisplayNode', ], }), ], + examples, }); diff --git a/src/v1/nodes/displayNodes/EnumVariantDisplayNode.examples.ts b/src/v1/nodes/displayNodes/EnumVariantDisplayNode.examples.ts new file mode 100644 index 00000000..7ccea835 --- /dev/null +++ b/src/v1/nodes/displayNodes/EnumVariantDisplayNode.examples.ts @@ -0,0 +1,32 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Relabelling a struct variant', + code( + 'typescript', + ` +enumStructVariantTypeNode( + 'buy', + structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') })]), + undefined, + { display: enumVariantDisplayNode({ label: 'Buy' }) }, +); +`, + ), + ), + example( + 'Hiding a tuple payload so only the label is shown', + code( + 'typescript', + ` +enumTupleVariantTypeNode( + 'increment', + tupleTypeNode([numberTypeNode('u64')]), + undefined, + { display: enumVariantDisplayNode({ label: 'Increment', skipInnerData: true }) }, +); +`, + ), + ), +]; diff --git a/src/v1/nodes/displayNodes/EnumVariantDisplayNode.ts b/src/v1/nodes/displayNodes/EnumVariantDisplayNode.ts index 3c91eea4..3aa97a65 100644 --- a/src/v1/nodes/displayNodes/EnumVariantDisplayNode.ts +++ b/src/v1/nodes/displayNodes/EnumVariantDisplayNode.ts @@ -1,4 +1,5 @@ import { boolean, defineNode, optionalAttribute, string } from '../../../api'; +import { examples } from './EnumVariantDisplayNode.examples'; export const enumVariantDisplayNode = defineNode('enumVariantDisplayNode', { docs: ['Display metadata for an enum variant: its label and whether to hide its inner payload.'], @@ -16,4 +17,5 @@ export const enumVariantDisplayNode = defineNode('enumVariantDisplayNode', { ], }), ], + examples, }); diff --git a/src/v1/nodes/displayNodes/InstructionAccountDisplayNode.examples.ts b/src/v1/nodes/displayNodes/InstructionAccountDisplayNode.examples.ts new file mode 100644 index 00000000..0eae36fe --- /dev/null +++ b/src/v1/nodes/displayNodes/InstructionAccountDisplayNode.examples.ts @@ -0,0 +1,32 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Relabelling an account in the fallback list', + code( + 'typescript', + ` +instructionAccountNode({ + name: 'destination', + isSigner: false, + isWritable: true, + display: instructionAccountDisplayNode({ label: 'To' }), +}); +`, + ), + ), + example( + 'Hiding an account once its value is surfaced elsewhere', + code( + 'typescript', + ` +instructionAccountNode({ + name: 'mint', + isSigner: false, + isWritable: false, + display: instructionAccountDisplayNode({ label: 'Token Mint', skip: 'whenInjected' }), +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/displayNodes/InstructionAccountDisplayNode.ts b/src/v1/nodes/displayNodes/InstructionAccountDisplayNode.ts index 650cae8f..42ca5cfa 100644 --- a/src/v1/nodes/displayNodes/InstructionAccountDisplayNode.ts +++ b/src/v1/nodes/displayNodes/InstructionAccountDisplayNode.ts @@ -1,4 +1,5 @@ import { defineNode, enumeration, optionalAttribute, string } from '../../../api'; +import { examples } from './InstructionAccountDisplayNode.examples'; export const instructionAccountDisplayNode = defineNode('instructionAccountDisplayNode', { docs: ['Display metadata for an instruction account: its label in the fallback list and whether it is shown.'], @@ -13,4 +14,5 @@ export const instructionAccountDisplayNode = defineNode('instructionAccountDispl docs: ['Whether the account is shown in the fallback list. Defaults to `"never"` (always shown).'], }), ], + examples, }); diff --git a/src/v1/nodes/displayNodes/InstructionDisplayNode.examples.ts b/src/v1/nodes/displayNodes/InstructionDisplayNode.examples.ts new file mode 100644 index 00000000..24ff694b --- /dev/null +++ b/src/v1/nodes/displayNodes/InstructionDisplayNode.examples.ts @@ -0,0 +1,36 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'An intent label plus an interpolated sentence', + code( + 'typescript', + ` +instructionNode({ + name: 'transferChecked', + display: instructionDisplayNode({ + intent: 'Transfer', + interpolatedIntent: 'Transfer \${data.amount} to \${accounts.destination}', + }), + // ...accounts and arguments +}); + +// intent => "Transfer" +// interpolated => "Transfer 1.5 USDC to 3Wnd5…5PxJX" +`, + ), + ), + example( + 'An intent label only, letting the renderer build the fallback list', + code( + 'typescript', + ` +instructionNode({ + name: 'closeAccount', + display: instructionDisplayNode({ intent: 'Close Account' }), + // ...accounts and arguments +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/displayNodes/InstructionDisplayNode.ts b/src/v1/nodes/displayNodes/InstructionDisplayNode.ts index 2c82657d..786de589 100644 --- a/src/v1/nodes/displayNodes/InstructionDisplayNode.ts +++ b/src/v1/nodes/displayNodes/InstructionDisplayNode.ts @@ -1,4 +1,5 @@ import { defineNode, optionalAttribute, string } from '../../../api'; +import { examples } from './InstructionDisplayNode.examples'; export const instructionDisplayNode = defineNode('instructionDisplayNode', { docs: [ @@ -17,4 +18,5 @@ export const instructionDisplayNode = defineNode('instructionDisplayNode', { ], }), ], + examples, }); diff --git a/src/v1/nodes/displayNodes/StringDisplayNode.examples.ts b/src/v1/nodes/displayNodes/StringDisplayNode.examples.ts new file mode 100644 index 00000000..62a2b052 --- /dev/null +++ b/src/v1/nodes/displayNodes/StringDisplayNode.examples.ts @@ -0,0 +1,26 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Displaying the whole string', + code( + 'typescript', + ` +stringTypeNode('utf8', { display: stringDisplayNode({}) }); + +// "SOLANA" => "SOLANA" +`, + ), + ), + example( + 'Displaying a leading slice', + code( + 'typescript', + ` +stringTypeNode('utf8', { display: stringDisplayNode({ sliceStart: 0, sliceEnd: 3 }) }); + +// "SOLANA" => "SOL" +`, + ), + ), +]; diff --git a/src/v1/nodes/displayNodes/StringDisplayNode.ts b/src/v1/nodes/displayNodes/StringDisplayNode.ts index c311f989..946f17c3 100644 --- a/src/v1/nodes/displayNodes/StringDisplayNode.ts +++ b/src/v1/nodes/displayNodes/StringDisplayNode.ts @@ -1,4 +1,5 @@ import { defineNode, optionalAttribute, u64 } from '../../../api'; +import { examples } from './StringDisplayNode.examples'; export const stringDisplayNode = defineNode('stringDisplayNode', { docs: [ @@ -19,4 +20,5 @@ export const stringDisplayNode = defineNode('stringDisplayNode', { ], }), ], + examples, }); diff --git a/src/v1/nodes/displayNodes/StructFieldDisplayNode.examples.ts b/src/v1/nodes/displayNodes/StructFieldDisplayNode.examples.ts new file mode 100644 index 00000000..33481755 --- /dev/null +++ b/src/v1/nodes/displayNodes/StructFieldDisplayNode.examples.ts @@ -0,0 +1,43 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Relabelling an instruction argument', + code( + 'typescript', + ` +instructionArgumentNode({ + name: 'amount', + type: numberTypeNode('u64'), + display: structFieldDisplayNode({ label: 'Amount' }), +}); +`, + ), + ), + example( + 'Hiding a discriminator argument from the fallback list', + code( + 'typescript', + ` +instructionArgumentNode({ + name: 'discriminator', + type: numberTypeNode('u8'), + display: structFieldDisplayNode({ skip: 'always' }), +}); +`, + ), + ), + example( + 'Flattening a nested struct into its parent with a label prefix', + code( + 'typescript', + ` +structFieldTypeNode({ + name: 'config', + type: definedTypeLinkNode('config'), + display: structFieldDisplayNode({ flatten: true, flattenPrefix: 'config.' }), +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/displayNodes/StructFieldDisplayNode.ts b/src/v1/nodes/displayNodes/StructFieldDisplayNode.ts index 94332318..80d94584 100644 --- a/src/v1/nodes/displayNodes/StructFieldDisplayNode.ts +++ b/src/v1/nodes/displayNodes/StructFieldDisplayNode.ts @@ -1,4 +1,5 @@ import { boolean, defineNode, enumeration, optionalAttribute, string } from '../../../api'; +import { examples } from './StructFieldDisplayNode.examples'; export const structFieldDisplayNode = defineNode('structFieldDisplayNode', { docs: [ @@ -29,4 +30,5 @@ export const structFieldDisplayNode = defineNode('structFieldDisplayNode', { ], }), ], + examples, }); diff --git a/src/v1/nodes/linkNodes/AccountLinkNode.examples.ts b/src/v1/nodes/linkNodes/AccountLinkNode.examples.ts new file mode 100644 index 00000000..53f23c22 --- /dev/null +++ b/src/v1/nodes/linkNodes/AccountLinkNode.examples.ts @@ -0,0 +1,14 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create an account link node from an account name', + code( + 'typescript', + ` +const node = accountLinkNode('myAccount'); +const nodeFromAnotherProgram = accountLinkNode('myAccount', 'myOtherProgram'); +`, + ), + ), +]; diff --git a/src/v1/nodes/linkNodes/AccountLinkNode.ts b/src/v1/nodes/linkNodes/AccountLinkNode.ts index 98f8ebd6..17ce63ba 100644 --- a/src/v1/nodes/linkNodes/AccountLinkNode.ts +++ b/src/v1/nodes/linkNodes/AccountLinkNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, node, optionalAttribute, stringIdentifier } from '../../../api'; +import { examples } from './AccountLinkNode.examples'; export const accountLinkNode = defineNode('accountLinkNode', { docs: ['A reference to an account defined elsewhere — possibly in a different program.'], @@ -10,4 +11,5 @@ export const accountLinkNode = defineNode('accountLinkNode', { docs: ['The name of the referenced account.'], }), ], + examples, }); diff --git a/src/v1/nodes/linkNodes/DefinedTypeLinkNode.examples.ts b/src/v1/nodes/linkNodes/DefinedTypeLinkNode.examples.ts new file mode 100644 index 00000000..6cc1e8c3 --- /dev/null +++ b/src/v1/nodes/linkNodes/DefinedTypeLinkNode.examples.ts @@ -0,0 +1,14 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a defined type link node from a type name', + code( + 'typescript', + ` +const node = definedTypeLinkNode('myDefinedType'); +const nodeFromAnotherProgram = definedTypeLinkNode('myDefinedType', 'myOtherProgram'); +`, + ), + ), +]; diff --git a/src/v1/nodes/linkNodes/DefinedTypeLinkNode.ts b/src/v1/nodes/linkNodes/DefinedTypeLinkNode.ts index 17c1b3a3..d9d81655 100644 --- a/src/v1/nodes/linkNodes/DefinedTypeLinkNode.ts +++ b/src/v1/nodes/linkNodes/DefinedTypeLinkNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, node, optionalAttribute, stringIdentifier } from '../../../api'; +import { examples } from './DefinedTypeLinkNode.examples'; export const definedTypeLinkNode = defineNode('definedTypeLinkNode', { docs: ['A reference to a defined type — possibly in a different program.'], @@ -10,4 +11,5 @@ export const definedTypeLinkNode = defineNode('definedTypeLinkNode', { docs: ['The name of the referenced defined type.'], }), ], + examples, }); diff --git a/src/v1/nodes/linkNodes/InstructionAccountLinkNode.examples.ts b/src/v1/nodes/linkNodes/InstructionAccountLinkNode.examples.ts new file mode 100644 index 00000000..467c47a3 --- /dev/null +++ b/src/v1/nodes/linkNodes/InstructionAccountLinkNode.examples.ts @@ -0,0 +1,23 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create an instruction account link node from an account name', + code( + 'typescript', + ` +// Links to an account in the current instruction. +const node = instructionAccountLinkNode('myAccount'); + +// Links to an account in another instruction but within the same program. +const nodeFromAnotherInstruction = instructionAccountLinkNode('myAccount', 'myOtherInstruction'); + +// Links to an account in another instruction from another program. +const nodeFromAnotherProgram = instructionAccountLinkNode( + 'myAccount', + instructionLinkNode('myOtherInstruction', 'myOtherProgram'), +); +`, + ), + ), +]; diff --git a/src/v1/nodes/linkNodes/InstructionAccountLinkNode.ts b/src/v1/nodes/linkNodes/InstructionAccountLinkNode.ts index a329bfa9..ba39dd6e 100644 --- a/src/v1/nodes/linkNodes/InstructionAccountLinkNode.ts +++ b/src/v1/nodes/linkNodes/InstructionAccountLinkNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, node, optionalAttribute, stringIdentifier } from '../../../api'; +import { examples } from './InstructionAccountLinkNode.examples'; export const instructionAccountLinkNode = defineNode('instructionAccountLinkNode', { docs: ['A reference to an account of another instruction.'], @@ -12,4 +13,5 @@ export const instructionAccountLinkNode = defineNode('instructionAccountLinkNode docs: ['The name of the referenced instruction account.'], }), ], + examples, }); diff --git a/src/v1/nodes/linkNodes/InstructionArgumentLinkNode.examples.ts b/src/v1/nodes/linkNodes/InstructionArgumentLinkNode.examples.ts new file mode 100644 index 00000000..518befe1 --- /dev/null +++ b/src/v1/nodes/linkNodes/InstructionArgumentLinkNode.examples.ts @@ -0,0 +1,23 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create an instruction argument link node from an argument name', + code( + 'typescript', + ` +// Links to an argument in the current instruction. +const node = instructionArgumentLinkNode('myArgument'); + +// Links to an argument in another instruction but within the same program. +const nodeFromAnotherInstruction = instructionArgumentLinkNode('myArgument', 'myOtherInstruction'); + +// Links to an argument in another instruction from another program. +const nodeFromAnotherProgram = instructionArgumentLinkNode( + 'myArgument', + instructionLinkNode('myOtherInstruction', 'myOtherProgram'), +); +`, + ), + ), +]; diff --git a/src/v1/nodes/linkNodes/InstructionArgumentLinkNode.ts b/src/v1/nodes/linkNodes/InstructionArgumentLinkNode.ts index 16799d78..79b2066c 100644 --- a/src/v1/nodes/linkNodes/InstructionArgumentLinkNode.ts +++ b/src/v1/nodes/linkNodes/InstructionArgumentLinkNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, node, optionalAttribute, stringIdentifier } from '../../../api'; +import { examples } from './InstructionArgumentLinkNode.examples'; export const instructionArgumentLinkNode = defineNode('instructionArgumentLinkNode', { docs: ['A reference to an argument of another instruction.'], @@ -12,4 +13,5 @@ export const instructionArgumentLinkNode = defineNode('instructionArgumentLinkNo docs: ['The name of the referenced instruction argument.'], }), ], + examples, }); diff --git a/src/v1/nodes/linkNodes/InstructionLinkNode.examples.ts b/src/v1/nodes/linkNodes/InstructionLinkNode.examples.ts new file mode 100644 index 00000000..86e97c30 --- /dev/null +++ b/src/v1/nodes/linkNodes/InstructionLinkNode.examples.ts @@ -0,0 +1,14 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create an instruction link node from an instruction name', + code( + 'typescript', + ` +const node = instructionLinkNode('myInstruction'); +const nodeFromAnotherProgram = instructionLinkNode('myInstruction', 'myOtherProgram'); +`, + ), + ), +]; diff --git a/src/v1/nodes/linkNodes/InstructionLinkNode.ts b/src/v1/nodes/linkNodes/InstructionLinkNode.ts index 63f507aa..18375322 100644 --- a/src/v1/nodes/linkNodes/InstructionLinkNode.ts +++ b/src/v1/nodes/linkNodes/InstructionLinkNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, node, optionalAttribute, stringIdentifier } from '../../../api'; +import { examples } from './InstructionLinkNode.examples'; export const instructionLinkNode = defineNode('instructionLinkNode', { docs: ['A reference to an instruction defined elsewhere — possibly in a different program.'], @@ -12,4 +13,5 @@ export const instructionLinkNode = defineNode('instructionLinkNode', { docs: ['The name of the referenced instruction.'], }), ], + examples, }); diff --git a/src/v1/nodes/linkNodes/PdaLinkNode.examples.ts b/src/v1/nodes/linkNodes/PdaLinkNode.examples.ts new file mode 100644 index 00000000..01305658 --- /dev/null +++ b/src/v1/nodes/linkNodes/PdaLinkNode.examples.ts @@ -0,0 +1,14 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a PDA link node from a PDA name', + code( + 'typescript', + ` +const node = pdaLinkNode('myPda'); +const nodeFromAnotherProgram = pdaLinkNode('myPda', 'myOtherProgram'); +`, + ), + ), +]; diff --git a/src/v1/nodes/linkNodes/PdaLinkNode.ts b/src/v1/nodes/linkNodes/PdaLinkNode.ts index 50ac4f82..fae6c084 100644 --- a/src/v1/nodes/linkNodes/PdaLinkNode.ts +++ b/src/v1/nodes/linkNodes/PdaLinkNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, node, optionalAttribute, stringIdentifier } from '../../../api'; +import { examples } from './PdaLinkNode.examples'; export const pdaLinkNode = defineNode('pdaLinkNode', { docs: ['A reference to a PDA defined elsewhere — possibly in a different program.'], @@ -10,4 +11,5 @@ export const pdaLinkNode = defineNode('pdaLinkNode', { docs: ['The name of the referenced PDA.'], }), ], + examples, }); diff --git a/src/v1/nodes/linkNodes/ProgramLinkNode.examples.ts b/src/v1/nodes/linkNodes/ProgramLinkNode.examples.ts new file mode 100644 index 00000000..5cd8d87c --- /dev/null +++ b/src/v1/nodes/linkNodes/ProgramLinkNode.examples.ts @@ -0,0 +1,13 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a program link node from a program name', + code( + 'typescript', + ` +const node = programLinkNode('myProgram'); +`, + ), + ), +]; diff --git a/src/v1/nodes/linkNodes/ProgramLinkNode.ts b/src/v1/nodes/linkNodes/ProgramLinkNode.ts index 8001c09c..64ea5d8b 100644 --- a/src/v1/nodes/linkNodes/ProgramLinkNode.ts +++ b/src/v1/nodes/linkNodes/ProgramLinkNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, stringIdentifier } from '../../../api'; +import { examples } from './ProgramLinkNode.examples'; export const programLinkNode = defineNode('programLinkNode', { docs: ['A reference to a program by name.'], @@ -7,4 +8,5 @@ export const programLinkNode = defineNode('programLinkNode', { docs: ['The name of the referenced program.'], }), ], + examples, }); diff --git a/src/v1/nodes/pdaSeedNodes/ConstantPdaSeedNode.examples.ts b/src/v1/nodes/pdaSeedNodes/ConstantPdaSeedNode.examples.ts new file mode 100644 index 00000000..97abd72b --- /dev/null +++ b/src/v1/nodes/pdaSeedNodes/ConstantPdaSeedNode.examples.ts @@ -0,0 +1,16 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'A PDA node with a UTF-8 constant seed', + code( + 'typescript', + ` +pdaNode({ + name: 'tickets', + seeds: [constantPdaSeedNodeFromString('utf8', 'tickets')], +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/pdaSeedNodes/ConstantPdaSeedNode.ts b/src/v1/nodes/pdaSeedNodes/ConstantPdaSeedNode.ts index b94c4c1d..fbe1d655 100644 --- a/src/v1/nodes/pdaSeedNodes/ConstantPdaSeedNode.ts +++ b/src/v1/nodes/pdaSeedNodes/ConstantPdaSeedNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, union } from '../../../api'; +import { examples } from './ConstantPdaSeedNode.examples'; export const constantPdaSeedNode = defineNode('constantPdaSeedNode', { docs: ['A PDA seed with a constant value (e.g. a UTF-8 string or a fixed byte sequence).'], @@ -10,4 +11,5 @@ export const constantPdaSeedNode = defineNode('constantPdaSeedNode', { docs: ['The constant value to use as the seed — either a literal value or the program ID placeholder.'], }), ], + examples, }); diff --git a/src/v1/nodes/pdaSeedNodes/VariablePdaSeedNode.examples.ts b/src/v1/nodes/pdaSeedNodes/VariablePdaSeedNode.examples.ts new file mode 100644 index 00000000..5287b785 --- /dev/null +++ b/src/v1/nodes/pdaSeedNodes/VariablePdaSeedNode.examples.ts @@ -0,0 +1,25 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a variable PDA seed node from a name and a type node', + code( + 'typescript', + ` +const node = variablePdaSeedNode('amount', numberTypeNode('u32')); +`, + ), + ), + example( + 'A PDA node with a public key variable seed', + code( + 'typescript', + ` +pdaNode({ + name: 'ticket', + seeds: [variablePdaSeedNode('authority', publicKeyTypeNode())], +}); +`, + ), + ), +]; diff --git a/src/v1/nodes/pdaSeedNodes/VariablePdaSeedNode.ts b/src/v1/nodes/pdaSeedNodes/VariablePdaSeedNode.ts index 8fdc06c4..1800d05d 100644 --- a/src/v1/nodes/pdaSeedNodes/VariablePdaSeedNode.ts +++ b/src/v1/nodes/pdaSeedNodes/VariablePdaSeedNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, docs, optionalAttribute, stringIdentifier, union } from '../../../api'; +import { examples } from './VariablePdaSeedNode.examples'; export const variablePdaSeedNode = defineNode('variablePdaSeedNode', { docs: ['A PDA seed whose value is provided at derivation time, identified by name.'], @@ -13,4 +14,5 @@ export const variablePdaSeedNode = defineNode('variablePdaSeedNode', { docs: ['The expected type of the seed value.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/AmountTypeNode.examples.ts b/src/v1/nodes/typeNodes/AmountTypeNode.examples.ts new file mode 100644 index 00000000..b14094d2 --- /dev/null +++ b/src/v1/nodes/typeNodes/AmountTypeNode.examples.ts @@ -0,0 +1,17 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + '2-decimals USD amount', + code( + 'typescript', + ` +amountTypeNode(numberTypeNode('u32'), 2, 'USD'); + +// 0.01 USD => 0x01000000 +// 10 USD => 0xE8030000 +// 400.60 USD => 0x7C9C0000 +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/AmountTypeNode.ts b/src/v1/nodes/typeNodes/AmountTypeNode.ts index 2971871c..1e7fa90f 100644 --- a/src/v1/nodes/typeNodes/AmountTypeNode.ts +++ b/src/v1/nodes/typeNodes/AmountTypeNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, nestedUnion, optionalAttribute, string, u32 } from '../../../api'; +import { examples } from './AmountTypeNode.examples'; export const amountTypeNode = defineNode('amountTypeNode', { docs: [ @@ -19,4 +20,5 @@ export const amountTypeNode = defineNode('amountTypeNode', { docs: ['The number type the amount wraps.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/ArrayTypeNode.examples.ts b/src/v1/nodes/typeNodes/ArrayTypeNode.examples.ts new file mode 100644 index 00000000..5b3a8838 --- /dev/null +++ b/src/v1/nodes/typeNodes/ArrayTypeNode.examples.ts @@ -0,0 +1,24 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create an array type node from a type node and a count node', + code( + 'typescript', + ` +const node = arrayTypeNode(publicKeyTypeNode(), prefixedCountNode(numberTypeNode('u32'))); +`, + ), + ), + example( + 'u32 prefixed array of u8 numbers', + code( + 'typescript', + ` +arrayTypeNode(numberTypeNode('u8'), prefixedCountNode(numberTypeNode('u32'))); + +// [1, 2, 3] => 0x03000000010203 +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/ArrayTypeNode.ts b/src/v1/nodes/typeNodes/ArrayTypeNode.ts index 20076623..ecb1fe59 100644 --- a/src/v1/nodes/typeNodes/ArrayTypeNode.ts +++ b/src/v1/nodes/typeNodes/ArrayTypeNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, union } from '../../../api'; +import { examples } from './ArrayTypeNode.examples'; export const arrayTypeNode = defineNode('arrayTypeNode', { docs: [ @@ -12,4 +13,5 @@ export const arrayTypeNode = defineNode('arrayTypeNode', { docs: ['The strategy used to determine the number of items.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/BooleanTypeNode.examples.ts b/src/v1/nodes/typeNodes/BooleanTypeNode.examples.ts new file mode 100644 index 00000000..085a3337 --- /dev/null +++ b/src/v1/nodes/typeNodes/BooleanTypeNode.examples.ts @@ -0,0 +1,28 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'u8 booleans', + code( + 'typescript', + ` +booleanTypeNode(); + +// true => 0x01 +// false => 0x00 +`, + ), + ), + example( + 'u32 booleans', + code( + 'typescript', + ` +booleanTypeNode(numberTypeNode('u32')); + +// true => 0x01000000 +// false => 0x00000000 +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/BooleanTypeNode.ts b/src/v1/nodes/typeNodes/BooleanTypeNode.ts index 6c97ea4d..9cc30a38 100644 --- a/src/v1/nodes/typeNodes/BooleanTypeNode.ts +++ b/src/v1/nodes/typeNodes/BooleanTypeNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, nestedUnion } from '../../../api'; +import { examples } from './BooleanTypeNode.examples'; export const booleanTypeNode = defineNode('booleanTypeNode', { docs: ['A boolean serialised as a numeric value. The wrapped number type determines the byte width.'], @@ -7,4 +8,5 @@ export const booleanTypeNode = defineNode('booleanTypeNode', { docs: ['The numeric type used to serialise the boolean.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/BytesTypeNode.examples.ts b/src/v1/nodes/typeNodes/BytesTypeNode.examples.ts new file mode 100644 index 00000000..d6fb1c39 --- /dev/null +++ b/src/v1/nodes/typeNodes/BytesTypeNode.examples.ts @@ -0,0 +1,13 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a bytes type node', + code( + 'typescript', + ` +const node = bytesTypeNode(); +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/BytesTypeNode.ts b/src/v1/nodes/typeNodes/BytesTypeNode.ts index d47362b8..41cd6964 100644 --- a/src/v1/nodes/typeNodes/BytesTypeNode.ts +++ b/src/v1/nodes/typeNodes/BytesTypeNode.ts @@ -1,8 +1,10 @@ import { defineNode } from '../../../api'; +import { examples } from './BytesTypeNode.examples'; export const bytesTypeNode = defineNode('bytesTypeNode', { docs: [ 'A raw sequence of bytes. Typically used inside a fixed-size, size-prefixed, or sentinel-terminated wrapper.', ], attributes: [], + examples, }); diff --git a/src/v1/nodes/typeNodes/DateTimeTypeNode.examples.ts b/src/v1/nodes/typeNodes/DateTimeTypeNode.examples.ts new file mode 100644 index 00000000..08e22dc1 --- /dev/null +++ b/src/v1/nodes/typeNodes/DateTimeTypeNode.examples.ts @@ -0,0 +1,24 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a date time type node from a number type node', + code( + 'typescript', + ` +const node = dateTimeTypeNode(numberTypeNode('u64')); +`, + ), + ), + example( + 'u64 unix datetime', + code( + 'typescript', + ` +dateTimeTypeNode(numberTypeNode('u64')); + +// 2024-06-27T14:57:56Z => 0xF47D7D6600000000 +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/DateTimeTypeNode.ts b/src/v1/nodes/typeNodes/DateTimeTypeNode.ts index ec554c13..0a257320 100644 --- a/src/v1/nodes/typeNodes/DateTimeTypeNode.ts +++ b/src/v1/nodes/typeNodes/DateTimeTypeNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, nestedUnion } from '../../../api'; +import { examples } from './DateTimeTypeNode.examples'; export const dateTimeTypeNode = defineNode('dateTimeTypeNode', { docs: [ @@ -9,4 +10,5 @@ export const dateTimeTypeNode = defineNode('dateTimeTypeNode', { docs: ['The numeric type used to serialise the timestamp.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/EnumEmptyVariantTypeNode.examples.ts b/src/v1/nodes/typeNodes/EnumEmptyVariantTypeNode.examples.ts new file mode 100644 index 00000000..fe950bcf --- /dev/null +++ b/src/v1/nodes/typeNodes/EnumEmptyVariantTypeNode.examples.ts @@ -0,0 +1,13 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create an empty enum variant type node from a name', + code( + 'typescript', + ` +const node = enumEmptyVariantTypeNode('myVariantName'); +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/EnumEmptyVariantTypeNode.ts b/src/v1/nodes/typeNodes/EnumEmptyVariantTypeNode.ts index daa7ffe3..6d604c50 100644 --- a/src/v1/nodes/typeNodes/EnumEmptyVariantTypeNode.ts +++ b/src/v1/nodes/typeNodes/EnumEmptyVariantTypeNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, node, optionalAttribute, stringIdentifier, u32 } from '../../../api'; +import { examples } from './EnumEmptyVariantTypeNode.examples'; export const enumEmptyVariantTypeNode = defineNode('enumEmptyVariantTypeNode', { docs: ['A unit-style variant of an enum that carries no payload.'], @@ -15,4 +16,5 @@ export const enumEmptyVariantTypeNode = defineNode('enumEmptyVariantTypeNode', { docs: ['Display metadata describing how the variant is presented.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/EnumStructVariantTypeNode.examples.ts b/src/v1/nodes/typeNodes/EnumStructVariantTypeNode.examples.ts new file mode 100644 index 00000000..a1744885 --- /dev/null +++ b/src/v1/nodes/typeNodes/EnumStructVariantTypeNode.examples.ts @@ -0,0 +1,19 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a struct enum variant type node from a name and a struct', + code( + 'typescript', + ` +const node = enumStructVariantTypeNode( + 'coordinates', + structTypeNode([ + structFieldTypeNode({ name: 'x', type: numberTypeNode('u32') }), + structFieldTypeNode({ name: 'y', type: numberTypeNode('u32') }), + ]), +); +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/EnumStructVariantTypeNode.ts b/src/v1/nodes/typeNodes/EnumStructVariantTypeNode.ts index ed31c132..bfac5889 100644 --- a/src/v1/nodes/typeNodes/EnumStructVariantTypeNode.ts +++ b/src/v1/nodes/typeNodes/EnumStructVariantTypeNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, nestedUnion, node, optionalAttribute, stringIdentifier, u32 } from '../../../api'; +import { examples } from './EnumStructVariantTypeNode.examples'; export const enumStructVariantTypeNode = defineNode('enumStructVariantTypeNode', { docs: ['A variant of an enum that carries a struct payload (named fields).'], @@ -18,4 +19,5 @@ export const enumStructVariantTypeNode = defineNode('enumStructVariantTypeNode', docs: ['Display metadata describing how the variant is presented.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/EnumTupleVariantTypeNode.examples.ts b/src/v1/nodes/typeNodes/EnumTupleVariantTypeNode.examples.ts new file mode 100644 index 00000000..68c14c54 --- /dev/null +++ b/src/v1/nodes/typeNodes/EnumTupleVariantTypeNode.examples.ts @@ -0,0 +1,13 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a tuple enum variant type node from a name and a tuple', + code( + 'typescript', + ` +const node = enumTupleVariantTypeNode('coordinates', tupleTypeNode([numberTypeNode('u32'), numberTypeNode('u32')])); +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/EnumTupleVariantTypeNode.ts b/src/v1/nodes/typeNodes/EnumTupleVariantTypeNode.ts index 16b2e655..4f8c11b9 100644 --- a/src/v1/nodes/typeNodes/EnumTupleVariantTypeNode.ts +++ b/src/v1/nodes/typeNodes/EnumTupleVariantTypeNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, nestedUnion, node, optionalAttribute, stringIdentifier, u32 } from '../../../api'; +import { examples } from './EnumTupleVariantTypeNode.examples'; export const enumTupleVariantTypeNode = defineNode('enumTupleVariantTypeNode', { docs: ['A variant of an enum that carries a tuple payload (positional fields).'], @@ -18,4 +19,5 @@ export const enumTupleVariantTypeNode = defineNode('enumTupleVariantTypeNode', { docs: ['Display metadata describing how the variant is presented.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/EnumTypeNode.examples.ts b/src/v1/nodes/typeNodes/EnumTypeNode.examples.ts new file mode 100644 index 00000000..f7acd4ad --- /dev/null +++ b/src/v1/nodes/typeNodes/EnumTypeNode.examples.ts @@ -0,0 +1,27 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Enum with u8 discriminator', + code( + 'typescript', + ` +enumTypeNode([ + enumEmptyVariantTypeNode('flip'), + enumTupleVariantTypeNode('rotate', tupleTypeNode([numberTypeNode('u32')])), + enumStructVariantTypeNode( + 'move', + structTypeNode([ + structFieldTypeNode({ name: 'x', type: numberTypeNode('u16') }), + structFieldTypeNode({ name: 'y', type: numberTypeNode('u16') }), + ]), + ), +]); + +// Flip => 0x00 +// Rotate (42) => 0x012A000000 +// Move { x: 1, y: 2 } => 0x0201000200 +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/EnumTypeNode.ts b/src/v1/nodes/typeNodes/EnumTypeNode.ts index 6489037c..96a3eac6 100644 --- a/src/v1/nodes/typeNodes/EnumTypeNode.ts +++ b/src/v1/nodes/typeNodes/EnumTypeNode.ts @@ -1,4 +1,5 @@ import { array, attribute, defineNode, nestedUnion, union } from '../../../api'; +import { examples } from './EnumTypeNode.examples'; export const enumTypeNode = defineNode('enumTypeNode', { docs: ['A tagged union: a numeric discriminator followed by one of several variant payloads.'], @@ -10,4 +11,5 @@ export const enumTypeNode = defineNode('enumTypeNode', { docs: ['The numeric type used to serialise the discriminator.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/FixedSizeTypeNode.examples.ts b/src/v1/nodes/typeNodes/FixedSizeTypeNode.examples.ts new file mode 100644 index 00000000..5f0f74a7 --- /dev/null +++ b/src/v1/nodes/typeNodes/FixedSizeTypeNode.examples.ts @@ -0,0 +1,36 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a fixed size type node from a type node and a byte length', + code( + 'typescript', + ` +const node = fixedSizeTypeNode(stringTypeNode('utf8'), 32); +`, + ), + ), + example( + 'Fixed UTF-8 strings', + code( + 'typescript', + ` +fixedSizeTypeNode(stringTypeNode('utf8'), 10); + +// Hello => 0x48656C6C6F0000000000 +`, + ), + ), + example( + 'Fixed byte arrays', + code( + 'typescript', + ` +fixedSizeTypeNode(bytesTypeNode(), 4); + +// [1, 2] => 0x01020000 +// [1, 2, 3, 4, 5] => 0x01020304 +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/FixedSizeTypeNode.ts b/src/v1/nodes/typeNodes/FixedSizeTypeNode.ts index c3003d3c..31606bd4 100644 --- a/src/v1/nodes/typeNodes/FixedSizeTypeNode.ts +++ b/src/v1/nodes/typeNodes/FixedSizeTypeNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, u64, union } from '../../../api'; +import { examples } from './FixedSizeTypeNode.examples'; export const fixedSizeTypeNode = defineNode('fixedSizeTypeNode', { docs: ['Wraps another type and asserts a fixed total byte size. Padding or truncation is applied as needed.'], @@ -10,4 +11,5 @@ export const fixedSizeTypeNode = defineNode('fixedSizeTypeNode', { docs: ['The wrapped type whose serialisation is constrained.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/HiddenPrefixTypeNode.examples.ts b/src/v1/nodes/typeNodes/HiddenPrefixTypeNode.examples.ts new file mode 100644 index 00000000..6738e8a6 --- /dev/null +++ b/src/v1/nodes/typeNodes/HiddenPrefixTypeNode.examples.ts @@ -0,0 +1,39 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a hidden prefix type node from a type node and constant value nodes', + code( + 'typescript', + ` +const node = hiddenPrefixTypeNode(numberTypeNode('u32'), [ + constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffff')), +]); +`, + ), + ), + example( + 'A number prefixed with 0xFFFF', + code( + 'typescript', + ` +hiddenPrefixTypeNode(numberTypeNode('u32'), [constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffff'))]); + +// 42 => 0xFFFF2A000000 +`, + ), + ), + example( + 'A fixed UTF-8 string prefixed with "Hello"', + code( + 'typescript', + ` +hiddenPrefixTypeNode(fixedSizeTypeNode(stringTypeNode('utf8'), 10), [ + constantValueNode(stringTypeNode('utf8'), stringValueNode('Hello')), +]); + +// World => 0x48656C6C6F576F726C640000000000 +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/HiddenPrefixTypeNode.ts b/src/v1/nodes/typeNodes/HiddenPrefixTypeNode.ts index 3f5ac142..94fe4b01 100644 --- a/src/v1/nodes/typeNodes/HiddenPrefixTypeNode.ts +++ b/src/v1/nodes/typeNodes/HiddenPrefixTypeNode.ts @@ -1,4 +1,5 @@ import { array, attribute, defineNode, node, union } from '../../../api'; +import { examples } from './HiddenPrefixTypeNode.examples'; export const hiddenPrefixTypeNode = defineNode('hiddenPrefixTypeNode', { docs: [ @@ -12,4 +13,5 @@ export const hiddenPrefixTypeNode = defineNode('hiddenPrefixTypeNode', { docs: ['The constant values written before the wrapped type, in order.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/HiddenSuffixTypeNode.examples.ts b/src/v1/nodes/typeNodes/HiddenSuffixTypeNode.examples.ts new file mode 100644 index 00000000..97c8ef93 --- /dev/null +++ b/src/v1/nodes/typeNodes/HiddenSuffixTypeNode.examples.ts @@ -0,0 +1,39 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a hidden suffix type node from a type node and constant value nodes', + code( + 'typescript', + ` +const node = hiddenSuffixTypeNode(numberTypeNode('u32'), [ + constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffff')), +]); +`, + ), + ), + example( + 'A number suffixed with 0xFFFF', + code( + 'typescript', + ` +hiddenSuffixTypeNode(numberTypeNode('u32'), [constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffff'))]); + +// 42 => 0x2A000000FFFF +`, + ), + ), + example( + 'A fixed UTF-8 string suffixed with "Hello"', + code( + 'typescript', + ` +hiddenSuffixTypeNode(fixedSizeTypeNode(stringTypeNode('utf8'), 10), [ + constantValueNode(stringTypeNode('utf8'), stringValueNode('Hello')), +]); + +// World => 0x576F726C64000000000048656c6c6F +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/HiddenSuffixTypeNode.ts b/src/v1/nodes/typeNodes/HiddenSuffixTypeNode.ts index fa58c644..12d1ebf5 100644 --- a/src/v1/nodes/typeNodes/HiddenSuffixTypeNode.ts +++ b/src/v1/nodes/typeNodes/HiddenSuffixTypeNode.ts @@ -1,4 +1,5 @@ import { array, attribute, defineNode, node, union } from '../../../api'; +import { examples } from './HiddenSuffixTypeNode.examples'; export const hiddenSuffixTypeNode = defineNode('hiddenSuffixTypeNode', { docs: [ @@ -12,4 +13,5 @@ export const hiddenSuffixTypeNode = defineNode('hiddenSuffixTypeNode', { docs: ['The constant values written after the wrapped type, in order.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/MapTypeNode.examples.ts b/src/v1/nodes/typeNodes/MapTypeNode.examples.ts new file mode 100644 index 00000000..b65dc4fb --- /dev/null +++ b/src/v1/nodes/typeNodes/MapTypeNode.examples.ts @@ -0,0 +1,28 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a map type node from a key type, a value type, and a count node', + code( + 'typescript', + ` +const node = mapTypeNode(publicKeyTypeNode(), numberTypeNode('u32'), prefixedCountNode(numberTypeNode('u32'))); +`, + ), + ), + example( + 'A histogram that counts letters', + code( + 'typescript', + ` +mapTypeNode( + fixedSizeTypeNode(stringTypeNode('utf8'), 1), // Key: Single UTF-8 character. + numberTypeNode('u16'), // Value: 16-bit unsigned integer. + prefixedCountNode(numberTypeNode('u8')), // Count: map length is prefixed with a u8. +); + +// { A: 42, B: 1, C: 16 } => 0x03412A00420100431000 +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/MapTypeNode.ts b/src/v1/nodes/typeNodes/MapTypeNode.ts index 599d7654..59e9cd7e 100644 --- a/src/v1/nodes/typeNodes/MapTypeNode.ts +++ b/src/v1/nodes/typeNodes/MapTypeNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, union } from '../../../api'; +import { examples } from './MapTypeNode.examples'; export const mapTypeNode = defineNode('mapTypeNode', { docs: [ @@ -16,4 +17,5 @@ export const mapTypeNode = defineNode('mapTypeNode', { docs: ['The strategy used to determine the number of entries.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/NumberTypeNode.examples.ts b/src/v1/nodes/typeNodes/NumberTypeNode.examples.ts new file mode 100644 index 00000000..7ef11fdd --- /dev/null +++ b/src/v1/nodes/typeNodes/NumberTypeNode.examples.ts @@ -0,0 +1,43 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Encoding `u32` integers', + code( + 'typescript', + ` +numberTypeNode('u32'); + +// 5 => 0x05000000 +// 42 => 0x2A000000 +// 65535 => 0xFFFF0000 +`, + ), + ), + example( + 'Encoding `f32` big-endian decimal numbers', + code( + 'typescript', + ` +numberTypeNode('f32', 'be'); + +// 1 => 0x3F800000 +// -42 => 0xC2280000 +// 3.1415 => 0x40490E56 +`, + ), + ), + example( + 'Encoding `shortU16` integers', + code( + 'typescript', + ` +numberTypeNode('shortU16'); + +// 42 => 0x2A +// 128 => 0x8001 +// 16384 => 0x808001 +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/NumberTypeNode.ts b/src/v1/nodes/typeNodes/NumberTypeNode.ts index f21b28f5..2e7bf70a 100644 --- a/src/v1/nodes/typeNodes/NumberTypeNode.ts +++ b/src/v1/nodes/typeNodes/NumberTypeNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, enumeration, optionalAttribute, union } from '../../../api'; +import { examples } from './NumberTypeNode.examples'; export const numberTypeNode = defineNode('numberTypeNode', { docs: ['A numeric type with a fixed wire format and byte order.'], @@ -13,4 +14,5 @@ export const numberTypeNode = defineNode('numberTypeNode', { docs: ['Display metadata describing how the number is presented.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/OptionTypeNode.examples.ts b/src/v1/nodes/typeNodes/OptionTypeNode.examples.ts new file mode 100644 index 00000000..1e55148b --- /dev/null +++ b/src/v1/nodes/typeNodes/OptionTypeNode.examples.ts @@ -0,0 +1,28 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'An optional UTF-8 with a u16 prefix', + code( + 'typescript', + ` +optionTypeNode(stringTypeNode('utf8'), { prefix: numberTypeNode('u16') }); + +// None => 0x0000 +// Some("Hello") => 0x010048656C6C6F +`, + ), + ), + example( + 'A fixed optional u32 number', + code( + 'typescript', + ` +optionTypeNode(numberTypeNode('u32'), { fixed: true }); + +// None => 0x0000000000 +// Some(42) => 0x012A000000 +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/OptionTypeNode.ts b/src/v1/nodes/typeNodes/OptionTypeNode.ts index df81de3b..a561f397 100644 --- a/src/v1/nodes/typeNodes/OptionTypeNode.ts +++ b/src/v1/nodes/typeNodes/OptionTypeNode.ts @@ -1,4 +1,5 @@ import { attribute, boolean, defineNode, nestedUnion, optionalAttribute, union } from '../../../api'; +import { examples } from './OptionTypeNode.examples'; export const optionTypeNode = defineNode('optionTypeNode', { docs: ['A value that may be present or absent (Some/None), with an explicit numeric prefix indicating presence.'], @@ -15,4 +16,5 @@ export const optionTypeNode = defineNode('optionTypeNode', { docs: ['The numeric type used as the presence flag.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/PostOffsetTypeNode.examples.ts b/src/v1/nodes/typeNodes/PostOffsetTypeNode.examples.ts new file mode 100644 index 00000000..1134abdf --- /dev/null +++ b/src/v1/nodes/typeNodes/PostOffsetTypeNode.examples.ts @@ -0,0 +1,45 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'A relative post-offset (the default strategy)', + code( + 'typescript', + ` +postOffsetTypeNode(numberTypeNode('u32'), 2); +`, + ), + ), + example( + 'An absolute post-offset from the end of the buffer', + code( + 'typescript', + ` +postOffsetTypeNode(numberTypeNode('u32'), -2, 'absolute'); +`, + ), + ), + example( + 'A right-padded u32 number', + code( + 'typescript', + ` +postOffsetTypeNode(numberTypeNode('u32'), 4, 'padded'); + +// 42 => 0x2A00000000000000 +`, + ), + ), + example( + 'A u32 number overwritten by a u16 number', + code( + 'typescript', + ` +tupleTypeNode([postOffsetTypeNode(numberTypeNode('u32'), -2), numberTypeNode('u16')]); + +// [1, 2] => 0x01000200 +// [0xFFFFFFFF, 42] => 0xFFFF2A00 +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/PostOffsetTypeNode.ts b/src/v1/nodes/typeNodes/PostOffsetTypeNode.ts index c7bf3940..ff260e78 100644 --- a/src/v1/nodes/typeNodes/PostOffsetTypeNode.ts +++ b/src/v1/nodes/typeNodes/PostOffsetTypeNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, enumeration, i64, union } from '../../../api'; +import { examples } from './PostOffsetTypeNode.examples'; export const postOffsetTypeNode = defineNode('postOffsetTypeNode', { docs: [ @@ -15,4 +16,5 @@ export const postOffsetTypeNode = defineNode('postOffsetTypeNode', { docs: ['The wrapped type whose serialisation is followed by the offset.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/PreOffsetTypeNode.examples.ts b/src/v1/nodes/typeNodes/PreOffsetTypeNode.examples.ts new file mode 100644 index 00000000..dfa26584 --- /dev/null +++ b/src/v1/nodes/typeNodes/PreOffsetTypeNode.examples.ts @@ -0,0 +1,45 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'A relative pre-offset (the default strategy)', + code( + 'typescript', + ` +preOffsetTypeNode(numberTypeNode('u32'), 2); +`, + ), + ), + example( + 'An absolute pre-offset', + code( + 'typescript', + ` +preOffsetTypeNode(numberTypeNode('u32'), -2, 'absolute'); +`, + ), + ), + example( + 'A left-padded u32 number', + code( + 'typescript', + ` +preOffsetTypeNode(numberTypeNode('u32'), 4, 'padded'); + +// 42 => 0x000000002A000000 +`, + ), + ), + example( + 'A u32 number overwritten by a u16 number', + code( + 'typescript', + ` +tupleTypeNode([numberTypeNode('u32'), preOffsetTypeNode(numberTypeNode('u16'), -2)]); + +// [1, 2] => 0x01000200 +// [0xFFFFFFFF, 42] => 0xFFFF2A00 +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/PreOffsetTypeNode.ts b/src/v1/nodes/typeNodes/PreOffsetTypeNode.ts index 68333898..4def8e74 100644 --- a/src/v1/nodes/typeNodes/PreOffsetTypeNode.ts +++ b/src/v1/nodes/typeNodes/PreOffsetTypeNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, enumeration, i64, union } from '../../../api'; +import { examples } from './PreOffsetTypeNode.examples'; export const preOffsetTypeNode = defineNode('preOffsetTypeNode', { docs: [ @@ -15,4 +16,5 @@ export const preOffsetTypeNode = defineNode('preOffsetTypeNode', { docs: ['The wrapped type whose serialisation is preceded by the offset.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/PublicKeyTypeNode.examples.ts b/src/v1/nodes/typeNodes/PublicKeyTypeNode.examples.ts new file mode 100644 index 00000000..d6002dfb --- /dev/null +++ b/src/v1/nodes/typeNodes/PublicKeyTypeNode.examples.ts @@ -0,0 +1,13 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a public key type node', + code( + 'typescript', + ` +const node = publicKeyTypeNode(); +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/PublicKeyTypeNode.ts b/src/v1/nodes/typeNodes/PublicKeyTypeNode.ts index 1e2b7638..cf58500d 100644 --- a/src/v1/nodes/typeNodes/PublicKeyTypeNode.ts +++ b/src/v1/nodes/typeNodes/PublicKeyTypeNode.ts @@ -1,6 +1,8 @@ import { defineNode } from '../../../api'; +import { examples } from './PublicKeyTypeNode.examples'; export const publicKeyTypeNode = defineNode('publicKeyTypeNode', { docs: ['A 32-byte Solana public key.'], attributes: [], + examples, }); diff --git a/src/v1/nodes/typeNodes/RemainderOptionTypeNode.examples.ts b/src/v1/nodes/typeNodes/RemainderOptionTypeNode.examples.ts new file mode 100644 index 00000000..bc9df571 --- /dev/null +++ b/src/v1/nodes/typeNodes/RemainderOptionTypeNode.examples.ts @@ -0,0 +1,16 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'An optional UTF-8 string using remaining bytes', + code( + 'typescript', + ` +remainderOptionTypeNode(stringTypeNode('utf8')); + +// None => 0x +// Some("Hello") => 0x48656C6C6F +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/RemainderOptionTypeNode.ts b/src/v1/nodes/typeNodes/RemainderOptionTypeNode.ts index cdc8d70b..bb89bebe 100644 --- a/src/v1/nodes/typeNodes/RemainderOptionTypeNode.ts +++ b/src/v1/nodes/typeNodes/RemainderOptionTypeNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, union } from '../../../api'; +import { examples } from './RemainderOptionTypeNode.examples'; export const remainderOptionTypeNode = defineNode('remainderOptionTypeNode', { docs: [ @@ -9,4 +10,5 @@ export const remainderOptionTypeNode = defineNode('remainderOptionTypeNode', { docs: ['The type carried by the option when present.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/SentinelTypeNode.examples.ts b/src/v1/nodes/typeNodes/SentinelTypeNode.examples.ts new file mode 100644 index 00000000..88b8a793 --- /dev/null +++ b/src/v1/nodes/typeNodes/SentinelTypeNode.examples.ts @@ -0,0 +1,15 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'A UTF-8 string terminated by 0xFF', + code( + 'typescript', + ` +sentinelTypeNode(stringTypeNode('utf8'), constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ff'))); + +// Hello => 0x48656C6C6FFF +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/SentinelTypeNode.ts b/src/v1/nodes/typeNodes/SentinelTypeNode.ts index 663d2a80..0dd936be 100644 --- a/src/v1/nodes/typeNodes/SentinelTypeNode.ts +++ b/src/v1/nodes/typeNodes/SentinelTypeNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, node, union } from '../../../api'; +import { examples } from './SentinelTypeNode.examples'; export const sentinelTypeNode = defineNode('sentinelTypeNode', { docs: [ @@ -12,4 +13,5 @@ export const sentinelTypeNode = defineNode('sentinelTypeNode', { docs: ['The constant value written immediately after the wrapped type to mark its end.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/SetTypeNode.examples.ts b/src/v1/nodes/typeNodes/SetTypeNode.examples.ts new file mode 100644 index 00000000..8be9a678 --- /dev/null +++ b/src/v1/nodes/typeNodes/SetTypeNode.examples.ts @@ -0,0 +1,15 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'u32 prefixed set of u8 numbers', + code( + 'typescript', + ` +setTypeNode(numberTypeNode('u8'), prefixedCountNode(numberTypeNode('u32'))); + +// Set (1, 2, 3) => 0x03000000010203 +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/SetTypeNode.ts b/src/v1/nodes/typeNodes/SetTypeNode.ts index 76184777..e034c831 100644 --- a/src/v1/nodes/typeNodes/SetTypeNode.ts +++ b/src/v1/nodes/typeNodes/SetTypeNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, union } from '../../../api'; +import { examples } from './SetTypeNode.examples'; export const setTypeNode = defineNode('setTypeNode', { docs: [ @@ -12,4 +13,5 @@ export const setTypeNode = defineNode('setTypeNode', { docs: ['The strategy used to determine the number of items.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/SizePrefixTypeNode.examples.ts b/src/v1/nodes/typeNodes/SizePrefixTypeNode.examples.ts new file mode 100644 index 00000000..5ef52062 --- /dev/null +++ b/src/v1/nodes/typeNodes/SizePrefixTypeNode.examples.ts @@ -0,0 +1,16 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'A UTF-8 string prefixed with a u16 size', + code( + 'typescript', + ` +sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u16')); + +// "" => 0x0000 +// "Hello" => 0x050048656C6C6F +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/SizePrefixTypeNode.ts b/src/v1/nodes/typeNodes/SizePrefixTypeNode.ts index 5724d7f2..6716bf77 100644 --- a/src/v1/nodes/typeNodes/SizePrefixTypeNode.ts +++ b/src/v1/nodes/typeNodes/SizePrefixTypeNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, nestedUnion, union } from '../../../api'; +import { examples } from './SizePrefixTypeNode.examples'; export const sizePrefixTypeNode = defineNode('sizePrefixTypeNode', { docs: ['Wraps another type with a numeric prefix indicating the byte length of the wrapped type.'], @@ -10,4 +11,5 @@ export const sizePrefixTypeNode = defineNode('sizePrefixTypeNode', { docs: ['The numeric type used as the size prefix.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/SolAmountTypeNode.examples.ts b/src/v1/nodes/typeNodes/SolAmountTypeNode.examples.ts new file mode 100644 index 00000000..382a260d --- /dev/null +++ b/src/v1/nodes/typeNodes/SolAmountTypeNode.examples.ts @@ -0,0 +1,16 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'u64 Solana amounts', + code( + 'typescript', + ` +solAmountTypeNode(numberTypeNode('u64')); + +// 1.5 SOL => 0x002F685900000000 +// 300 SOL => 0x00B864D945000000 +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/SolAmountTypeNode.ts b/src/v1/nodes/typeNodes/SolAmountTypeNode.ts index 1ad4c0c7..672f55a2 100644 --- a/src/v1/nodes/typeNodes/SolAmountTypeNode.ts +++ b/src/v1/nodes/typeNodes/SolAmountTypeNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, nestedUnion } from '../../../api'; +import { examples } from './SolAmountTypeNode.examples'; export const solAmountTypeNode = defineNode('solAmountTypeNode', { docs: ['A SOL amount expressed in lamports under the wrapped numeric type.'], @@ -7,4 +8,5 @@ export const solAmountTypeNode = defineNode('solAmountTypeNode', { docs: ['The numeric type used to serialise the lamport amount.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/StringTypeNode.examples.ts b/src/v1/nodes/typeNodes/StringTypeNode.examples.ts new file mode 100644 index 00000000..89394b9e --- /dev/null +++ b/src/v1/nodes/typeNodes/StringTypeNode.examples.ts @@ -0,0 +1,13 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a string type node from an encoding', + code( + 'typescript', + ` +const node = stringTypeNode('utf8'); +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/StringTypeNode.ts b/src/v1/nodes/typeNodes/StringTypeNode.ts index 41f7d466..a976bb4c 100644 --- a/src/v1/nodes/typeNodes/StringTypeNode.ts +++ b/src/v1/nodes/typeNodes/StringTypeNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, enumeration, node, optionalAttribute } from '../../../api'; +import { examples } from './StringTypeNode.examples'; export const stringTypeNode = defineNode('stringTypeNode', { docs: [ @@ -14,4 +15,5 @@ export const stringTypeNode = defineNode('stringTypeNode', { docs: ['Display metadata describing how the string is presented.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/StructFieldTypeNode.examples.ts b/src/v1/nodes/typeNodes/StructFieldTypeNode.examples.ts new file mode 100644 index 00000000..356e12b7 --- /dev/null +++ b/src/v1/nodes/typeNodes/StructFieldTypeNode.examples.ts @@ -0,0 +1,20 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'A struct field with a default value', + code( + 'typescript', + ` +structFieldTypeNode({ + name: 'age', + type: numberTypeNode('u8'), + defaultValue: numberValueNode(42), +}); + +// {} => 0x2A +// { age: 29 } => 0x1D +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/StructFieldTypeNode.ts b/src/v1/nodes/typeNodes/StructFieldTypeNode.ts index 08661fcd..a4a776c6 100644 --- a/src/v1/nodes/typeNodes/StructFieldTypeNode.ts +++ b/src/v1/nodes/typeNodes/StructFieldTypeNode.ts @@ -8,6 +8,7 @@ import { stringIdentifier, union, } from '../../../api'; +import { examples } from './StructFieldTypeNode.examples'; export const structFieldTypeNode = defineNode('structFieldTypeNode', { docs: ['A named field within a struct type.'], @@ -31,4 +32,5 @@ export const structFieldTypeNode = defineNode('structFieldTypeNode', { docs: ['Display metadata describing how the field is presented.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/StructTypeNode.examples.ts b/src/v1/nodes/typeNodes/StructTypeNode.examples.ts new file mode 100644 index 00000000..375c1adc --- /dev/null +++ b/src/v1/nodes/typeNodes/StructTypeNode.examples.ts @@ -0,0 +1,18 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + "A struct storing a person's name and age", + code( + 'typescript', + ` +structTypeNode([ + structFieldTypeNode({ name: 'name', type: fixedSizeTypeNode(stringTypeNode('utf8'), 10) }), + structFieldTypeNode({ name: 'age', type: numberTypeNode('u8') }), +]); + +// { name: Alice, age: 42 } => 0x416C69636500000000002A +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/StructTypeNode.ts b/src/v1/nodes/typeNodes/StructTypeNode.ts index e79f480b..0912f00e 100644 --- a/src/v1/nodes/typeNodes/StructTypeNode.ts +++ b/src/v1/nodes/typeNodes/StructTypeNode.ts @@ -1,4 +1,5 @@ import { array, attribute, defineNode, node } from '../../../api'; +import { examples } from './StructTypeNode.examples'; export const structTypeNode = defineNode('structTypeNode', { docs: [ @@ -9,4 +10,5 @@ export const structTypeNode = defineNode('structTypeNode', { docs: ['The fields of the struct, in declaration order.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/TupleTypeNode.examples.ts b/src/v1/nodes/typeNodes/TupleTypeNode.examples.ts new file mode 100644 index 00000000..3666054d --- /dev/null +++ b/src/v1/nodes/typeNodes/TupleTypeNode.examples.ts @@ -0,0 +1,15 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + "A tuple storing a person's name and age", + code( + 'typescript', + ` +tupleTypeNode([fixedSizeTypeNode(stringTypeNode('utf8'), 10), numberTypeNode('u8')]); + +// (Alice, 42) => 0x416C69636500000000002A +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/TupleTypeNode.ts b/src/v1/nodes/typeNodes/TupleTypeNode.ts index 21022d2a..f526de28 100644 --- a/src/v1/nodes/typeNodes/TupleTypeNode.ts +++ b/src/v1/nodes/typeNodes/TupleTypeNode.ts @@ -1,4 +1,5 @@ import { array, attribute, defineNode, union } from '../../../api'; +import { examples } from './TupleTypeNode.examples'; export const tupleTypeNode = defineNode('tupleTypeNode', { docs: ['A heterogeneous fixed-length sequence in which each positional slot has its own type.'], @@ -7,4 +8,5 @@ export const tupleTypeNode = defineNode('tupleTypeNode', { docs: ['The type of each positional slot, in order.'], }), ], + examples, }); diff --git a/src/v1/nodes/typeNodes/ZeroableOptionTypeNode.examples.ts b/src/v1/nodes/typeNodes/ZeroableOptionTypeNode.examples.ts new file mode 100644 index 00000000..03f75f52 --- /dev/null +++ b/src/v1/nodes/typeNodes/ZeroableOptionTypeNode.examples.ts @@ -0,0 +1,28 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'a u32 zeroable option', + code( + 'typescript', + ` +zeroableOptionTypeNode(numberTypeNode('u32')); + +// None => 0x00000000 +// Some(42) => 0x2A000000 +`, + ), + ), + example( + 'a u32 zeroable option with a custom zero value', + code( + 'typescript', + ` +zeroableOptionTypeNode(numberTypeNode('u32'), constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffffffff'))); + +// None => 0xFFFFFFFF +// Some(42) => 0x2A000000 +`, + ), + ), +]; diff --git a/src/v1/nodes/typeNodes/ZeroableOptionTypeNode.ts b/src/v1/nodes/typeNodes/ZeroableOptionTypeNode.ts index 56ce157b..20cb9a69 100644 --- a/src/v1/nodes/typeNodes/ZeroableOptionTypeNode.ts +++ b/src/v1/nodes/typeNodes/ZeroableOptionTypeNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, node, optionalAttribute, union } from '../../../api'; +import { examples } from './ZeroableOptionTypeNode.examples'; export const zeroableOptionTypeNode = defineNode('zeroableOptionTypeNode', { docs: ['An optional value whose absence is signalled by a designated zero value rather than a presence flag.'], @@ -12,4 +13,5 @@ export const zeroableOptionTypeNode = defineNode('zeroableOptionTypeNode', { ], }), ], + examples, }); diff --git a/src/v1/nodes/valueNodes/ArrayValueNode.examples.ts b/src/v1/nodes/valueNodes/ArrayValueNode.examples.ts new file mode 100644 index 00000000..9d82d7e7 --- /dev/null +++ b/src/v1/nodes/valueNodes/ArrayValueNode.examples.ts @@ -0,0 +1,13 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create an array value node from value nodes', + code( + 'typescript', + ` +const node = arrayValueNode([numberValueNode(1), numberValueNode(2), numberValueNode(3)]); +`, + ), + ), +]; diff --git a/src/v1/nodes/valueNodes/ArrayValueNode.ts b/src/v1/nodes/valueNodes/ArrayValueNode.ts index fe482878..f16ac828 100644 --- a/src/v1/nodes/valueNodes/ArrayValueNode.ts +++ b/src/v1/nodes/valueNodes/ArrayValueNode.ts @@ -1,4 +1,5 @@ import { array, attribute, defineNode, union } from '../../../api'; +import { examples } from './ArrayValueNode.examples'; export const arrayValueNode = defineNode('arrayValueNode', { docs: ['A concrete array value: a list of value nodes.'], @@ -7,4 +8,5 @@ export const arrayValueNode = defineNode('arrayValueNode', { docs: ['The items of the array, in order.'], }), ], + examples, }); diff --git a/src/v1/nodes/valueNodes/BooleanValueNode.examples.ts b/src/v1/nodes/valueNodes/BooleanValueNode.examples.ts new file mode 100644 index 00000000..de8e8fb6 --- /dev/null +++ b/src/v1/nodes/valueNodes/BooleanValueNode.examples.ts @@ -0,0 +1,13 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a boolean value node from a boolean', + code( + 'typescript', + ` +const node = booleanValueNode(true); +`, + ), + ), +]; diff --git a/src/v1/nodes/valueNodes/BooleanValueNode.ts b/src/v1/nodes/valueNodes/BooleanValueNode.ts index 66cf5b30..166c419d 100644 --- a/src/v1/nodes/valueNodes/BooleanValueNode.ts +++ b/src/v1/nodes/valueNodes/BooleanValueNode.ts @@ -1,4 +1,5 @@ import { attribute, boolean, defineNode } from '../../../api'; +import { examples } from './BooleanValueNode.examples'; export const booleanValueNode = defineNode('booleanValueNode', { docs: ['A concrete boolean value.'], @@ -7,4 +8,5 @@ export const booleanValueNode = defineNode('booleanValueNode', { docs: ['The boolean value.'], }), ], + examples, }); diff --git a/src/v1/nodes/valueNodes/BytesValueNode.examples.ts b/src/v1/nodes/valueNodes/BytesValueNode.examples.ts new file mode 100644 index 00000000..b3e580ae --- /dev/null +++ b/src/v1/nodes/valueNodes/BytesValueNode.examples.ts @@ -0,0 +1,14 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a bytes value node from an encoding and data', + code( + 'typescript', + ` +const node = bytesValueNode('base16', '010203'); +const utf8Node = bytesValueNode('utf8', 'Hello'); +`, + ), + ), +]; diff --git a/src/v1/nodes/valueNodes/BytesValueNode.ts b/src/v1/nodes/valueNodes/BytesValueNode.ts index 76df9867..6789d3e7 100644 --- a/src/v1/nodes/valueNodes/BytesValueNode.ts +++ b/src/v1/nodes/valueNodes/BytesValueNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, enumeration, string } from '../../../api'; +import { examples } from './BytesValueNode.examples'; export const bytesValueNode = defineNode('bytesValueNode', { docs: ['A concrete bytes value, encoded as text in the chosen encoding.'], @@ -10,4 +11,5 @@ export const bytesValueNode = defineNode('bytesValueNode', { docs: ['The encoding used to represent the bytes as text.'], }), ], + examples, }); diff --git a/src/v1/nodes/valueNodes/ConstantValueNode.examples.ts b/src/v1/nodes/valueNodes/ConstantValueNode.examples.ts new file mode 100644 index 00000000..ec76f2c2 --- /dev/null +++ b/src/v1/nodes/valueNodes/ConstantValueNode.examples.ts @@ -0,0 +1,13 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a constant value node from a type and a value node', + code( + 'typescript', + ` +const node = constantValueNode(numberTypeNode('u32'), numberValueNode(42)); +`, + ), + ), +]; diff --git a/src/v1/nodes/valueNodes/ConstantValueNode.ts b/src/v1/nodes/valueNodes/ConstantValueNode.ts index d749bfee..83be391b 100644 --- a/src/v1/nodes/valueNodes/ConstantValueNode.ts +++ b/src/v1/nodes/valueNodes/ConstantValueNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, union } from '../../../api'; +import { examples } from './ConstantValueNode.examples'; export const constantValueNode = defineNode('constantValueNode', { docs: ['A typed constant: a type node paired with a concrete value node.'], @@ -10,4 +11,5 @@ export const constantValueNode = defineNode('constantValueNode', { docs: ['The concrete value of the constant.'], }), ], + examples, }); diff --git a/src/v1/nodes/valueNodes/EnumValueNode.examples.ts b/src/v1/nodes/valueNodes/EnumValueNode.examples.ts new file mode 100644 index 00000000..cf8e4039 --- /dev/null +++ b/src/v1/nodes/valueNodes/EnumValueNode.examples.ts @@ -0,0 +1,23 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create an enum value node from an enum, a variant, and an optional value', + code( + 'typescript', + ` +const node = enumValueNode('myEnum', 'myVariant'); +const nodeWithExplicitEnum = enumValueNode(definedTypeLinkNode('myEnum'), 'myVariant'); + +const nodeWithData = enumValueNode( + 'myEnum', + 'myVariantWithData', + structValueNode([ + structFieldValueNode('name', stringValueNode('Alice')), + structFieldValueNode('age', numberValueNode(42)), + ]), +); +`, + ), + ), +]; diff --git a/src/v1/nodes/valueNodes/EnumValueNode.ts b/src/v1/nodes/valueNodes/EnumValueNode.ts index 05b4d2a8..5ce22f73 100644 --- a/src/v1/nodes/valueNodes/EnumValueNode.ts +++ b/src/v1/nodes/valueNodes/EnumValueNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, node, optionalAttribute, stringIdentifier, union } from '../../../api'; +import { examples } from './EnumValueNode.examples'; export const enumValueNode = defineNode('enumValueNode', { docs: ['A concrete value of a defined enum: a variant identifier plus an optional payload.'], @@ -16,4 +17,5 @@ export const enumValueNode = defineNode('enumValueNode', { ], }), ], + examples, }); diff --git a/src/v1/nodes/valueNodes/MapEntryValueNode.examples.ts b/src/v1/nodes/valueNodes/MapEntryValueNode.examples.ts new file mode 100644 index 00000000..a1ea79ce --- /dev/null +++ b/src/v1/nodes/valueNodes/MapEntryValueNode.examples.ts @@ -0,0 +1,13 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a map entry value node from a key and a value', + code( + 'typescript', + ` +const node = mapEntryValueNode(stringValueNode('total'), numberValueNode(42)); +`, + ), + ), +]; diff --git a/src/v1/nodes/valueNodes/MapEntryValueNode.ts b/src/v1/nodes/valueNodes/MapEntryValueNode.ts index 2670df0b..ff3f1e38 100644 --- a/src/v1/nodes/valueNodes/MapEntryValueNode.ts +++ b/src/v1/nodes/valueNodes/MapEntryValueNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, union } from '../../../api'; +import { examples } from './MapEntryValueNode.examples'; export const mapEntryValueNode = defineNode('mapEntryValueNode', { docs: ['A single (key, value) pair inside a `mapValueNode`.'], @@ -10,4 +11,5 @@ export const mapEntryValueNode = defineNode('mapEntryValueNode', { docs: ['The entry value.'], }), ], + examples, }); diff --git a/src/v1/nodes/valueNodes/MapValueNode.examples.ts b/src/v1/nodes/valueNodes/MapValueNode.examples.ts new file mode 100644 index 00000000..04aa501e --- /dev/null +++ b/src/v1/nodes/valueNodes/MapValueNode.examples.ts @@ -0,0 +1,17 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a map value node from entries', + code( + 'typescript', + ` +const node = mapValueNode([ + mapEntryValueNode(stringValueNode('apples'), numberValueNode(12)), + mapEntryValueNode(stringValueNode('bananas'), numberValueNode(34)), + mapEntryValueNode(stringValueNode('carrots'), numberValueNode(56)), +]); +`, + ), + ), +]; diff --git a/src/v1/nodes/valueNodes/MapValueNode.ts b/src/v1/nodes/valueNodes/MapValueNode.ts index df3398ca..46ab6b64 100644 --- a/src/v1/nodes/valueNodes/MapValueNode.ts +++ b/src/v1/nodes/valueNodes/MapValueNode.ts @@ -1,4 +1,5 @@ import { array, attribute, defineNode, node } from '../../../api'; +import { examples } from './MapValueNode.examples'; export const mapValueNode = defineNode('mapValueNode', { docs: ['A concrete map value: a list of (key, value) entries.'], @@ -7,4 +8,5 @@ export const mapValueNode = defineNode('mapValueNode', { docs: ['The entries of the map, in order.'], }), ], + examples, }); diff --git a/src/v1/nodes/valueNodes/NoneValueNode.examples.ts b/src/v1/nodes/valueNodes/NoneValueNode.examples.ts new file mode 100644 index 00000000..be628df2 --- /dev/null +++ b/src/v1/nodes/valueNodes/NoneValueNode.examples.ts @@ -0,0 +1,13 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a none value node', + code( + 'typescript', + ` +const node = noneValueNode(); +`, + ), + ), +]; diff --git a/src/v1/nodes/valueNodes/NoneValueNode.ts b/src/v1/nodes/valueNodes/NoneValueNode.ts index 2c3c0d93..03a2d8eb 100644 --- a/src/v1/nodes/valueNodes/NoneValueNode.ts +++ b/src/v1/nodes/valueNodes/NoneValueNode.ts @@ -1,6 +1,8 @@ import { defineNode } from '../../../api'; +import { examples } from './NoneValueNode.examples'; export const noneValueNode = defineNode('noneValueNode', { docs: ['The "absent" value for an optional type.'], attributes: [], + examples, }); diff --git a/src/v1/nodes/valueNodes/NumberValueNode.examples.ts b/src/v1/nodes/valueNodes/NumberValueNode.examples.ts new file mode 100644 index 00000000..2d5bf8f7 --- /dev/null +++ b/src/v1/nodes/valueNodes/NumberValueNode.examples.ts @@ -0,0 +1,13 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a number value node from a number', + code( + 'typescript', + ` +const node = numberValueNode(42); +`, + ), + ), +]; diff --git a/src/v1/nodes/valueNodes/NumberValueNode.ts b/src/v1/nodes/valueNodes/NumberValueNode.ts index a3e47b12..36344d67 100644 --- a/src/v1/nodes/valueNodes/NumberValueNode.ts +++ b/src/v1/nodes/valueNodes/NumberValueNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, f64 } from '../../../api'; +import { examples } from './NumberValueNode.examples'; export const numberValueNode = defineNode('numberValueNode', { docs: [ @@ -10,4 +11,5 @@ export const numberValueNode = defineNode('numberValueNode', { docs: ['The numeric value.'], }), ], + examples, }); diff --git a/src/v1/nodes/valueNodes/PublicKeyValueNode.examples.ts b/src/v1/nodes/valueNodes/PublicKeyValueNode.examples.ts new file mode 100644 index 00000000..dc587e76 --- /dev/null +++ b/src/v1/nodes/valueNodes/PublicKeyValueNode.examples.ts @@ -0,0 +1,13 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a public key value node from a base58 public key', + code( + 'typescript', + ` +const node = publicKeyValueNode('7rA1KcBdW5hKmMasQdRVBFsD6T1nLtYuR6y59TJNgevR'); +`, + ), + ), +]; diff --git a/src/v1/nodes/valueNodes/PublicKeyValueNode.ts b/src/v1/nodes/valueNodes/PublicKeyValueNode.ts index 423fdc06..c29b35f1 100644 --- a/src/v1/nodes/valueNodes/PublicKeyValueNode.ts +++ b/src/v1/nodes/valueNodes/PublicKeyValueNode.ts @@ -1,4 +1,5 @@ import { address, attribute, defineNode, optionalAttribute, stringIdentifier } from '../../../api'; +import { examples } from './PublicKeyValueNode.examples'; export const publicKeyValueNode = defineNode('publicKeyValueNode', { docs: ['A concrete public key, with an optional symbolic identifier for the address.'], @@ -10,4 +11,5 @@ export const publicKeyValueNode = defineNode('publicKeyValueNode', { docs: ['A symbolic name for the address, useful in generated client code.'], }), ], + examples, }); diff --git a/src/v1/nodes/valueNodes/SetValueNode.examples.ts b/src/v1/nodes/valueNodes/SetValueNode.examples.ts new file mode 100644 index 00000000..0308f2ef --- /dev/null +++ b/src/v1/nodes/valueNodes/SetValueNode.examples.ts @@ -0,0 +1,13 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a set value node from value nodes', + code( + 'typescript', + ` +const node = setValueNode([numberValueNode(1), numberValueNode(2), numberValueNode(3)]); +`, + ), + ), +]; diff --git a/src/v1/nodes/valueNodes/SetValueNode.ts b/src/v1/nodes/valueNodes/SetValueNode.ts index dae59d88..d1f36803 100644 --- a/src/v1/nodes/valueNodes/SetValueNode.ts +++ b/src/v1/nodes/valueNodes/SetValueNode.ts @@ -1,4 +1,5 @@ import { array, attribute, defineNode, union } from '../../../api'; +import { examples } from './SetValueNode.examples'; export const setValueNode = defineNode('setValueNode', { docs: ['A concrete set value: a list of unique value nodes.'], @@ -7,4 +8,5 @@ export const setValueNode = defineNode('setValueNode', { docs: ['The items of the set.'], }), ], + examples, }); diff --git a/src/v1/nodes/valueNodes/SomeValueNode.examples.ts b/src/v1/nodes/valueNodes/SomeValueNode.examples.ts new file mode 100644 index 00000000..2a805c44 --- /dev/null +++ b/src/v1/nodes/valueNodes/SomeValueNode.examples.ts @@ -0,0 +1,13 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a some value node from a value node', + code( + 'typescript', + ` +const node = someValueNode(numberValueNode(42)); +`, + ), + ), +]; diff --git a/src/v1/nodes/valueNodes/SomeValueNode.ts b/src/v1/nodes/valueNodes/SomeValueNode.ts index cc0fcff3..dbdc4c92 100644 --- a/src/v1/nodes/valueNodes/SomeValueNode.ts +++ b/src/v1/nodes/valueNodes/SomeValueNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, union } from '../../../api'; +import { examples } from './SomeValueNode.examples'; export const someValueNode = defineNode('someValueNode', { docs: ['The "present" value for an optional type, wrapping a concrete value node.'], @@ -7,4 +8,5 @@ export const someValueNode = defineNode('someValueNode', { docs: ['The wrapped value.'], }), ], + examples, }); diff --git a/src/v1/nodes/valueNodes/StringValueNode.examples.ts b/src/v1/nodes/valueNodes/StringValueNode.examples.ts new file mode 100644 index 00000000..8284114c --- /dev/null +++ b/src/v1/nodes/valueNodes/StringValueNode.examples.ts @@ -0,0 +1,13 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a string value node from a string', + code( + 'typescript', + ` +const node = stringValueNode('Hello'); +`, + ), + ), +]; diff --git a/src/v1/nodes/valueNodes/StringValueNode.ts b/src/v1/nodes/valueNodes/StringValueNode.ts index e61f94bc..49c74376 100644 --- a/src/v1/nodes/valueNodes/StringValueNode.ts +++ b/src/v1/nodes/valueNodes/StringValueNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, string } from '../../../api'; +import { examples } from './StringValueNode.examples'; export const stringValueNode = defineNode('stringValueNode', { docs: ['A concrete string value.'], @@ -7,4 +8,5 @@ export const stringValueNode = defineNode('stringValueNode', { docs: ['The string value.'], }), ], + examples, }); diff --git a/src/v1/nodes/valueNodes/StructFieldValueNode.examples.ts b/src/v1/nodes/valueNodes/StructFieldValueNode.examples.ts new file mode 100644 index 00000000..b03b89ae --- /dev/null +++ b/src/v1/nodes/valueNodes/StructFieldValueNode.examples.ts @@ -0,0 +1,13 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a struct field value node from a name and a value', + code( + 'typescript', + ` +const node = structFieldValueNode('age', numberValueNode(42)); +`, + ), + ), +]; diff --git a/src/v1/nodes/valueNodes/StructFieldValueNode.ts b/src/v1/nodes/valueNodes/StructFieldValueNode.ts index 43fa0576..c02ea5db 100644 --- a/src/v1/nodes/valueNodes/StructFieldValueNode.ts +++ b/src/v1/nodes/valueNodes/StructFieldValueNode.ts @@ -1,4 +1,5 @@ import { attribute, defineNode, stringIdentifier, union } from '../../../api'; +import { examples } from './StructFieldValueNode.examples'; export const structFieldValueNode = defineNode('structFieldValueNode', { docs: ['A named field of a `structValueNode`.'], @@ -10,4 +11,5 @@ export const structFieldValueNode = defineNode('structFieldValueNode', { docs: ['The concrete value of the field.'], }), ], + examples, }); diff --git a/src/v1/nodes/valueNodes/StructValueNode.examples.ts b/src/v1/nodes/valueNodes/StructValueNode.examples.ts new file mode 100644 index 00000000..87e83031 --- /dev/null +++ b/src/v1/nodes/valueNodes/StructValueNode.examples.ts @@ -0,0 +1,16 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a struct value node from field value nodes', + code( + 'typescript', + ` +const node = structValueNode([ + structFieldValueNode('name', stringValueNode('Alice')), + structFieldValueNode('age', numberValueNode(42)), +]); +`, + ), + ), +]; diff --git a/src/v1/nodes/valueNodes/StructValueNode.ts b/src/v1/nodes/valueNodes/StructValueNode.ts index 788d5639..75805efc 100644 --- a/src/v1/nodes/valueNodes/StructValueNode.ts +++ b/src/v1/nodes/valueNodes/StructValueNode.ts @@ -1,4 +1,5 @@ import { array, attribute, defineNode, node } from '../../../api'; +import { examples } from './StructValueNode.examples'; export const structValueNode = defineNode('structValueNode', { docs: ['A concrete struct value: a list of named field values.'], @@ -7,4 +8,5 @@ export const structValueNode = defineNode('structValueNode', { docs: ['The named fields of the struct value.'], }), ], + examples, }); diff --git a/src/v1/nodes/valueNodes/TupleValueNode.examples.ts b/src/v1/nodes/valueNodes/TupleValueNode.examples.ts new file mode 100644 index 00000000..948c394d --- /dev/null +++ b/src/v1/nodes/valueNodes/TupleValueNode.examples.ts @@ -0,0 +1,13 @@ +import { code, example, type DocExamples } from '../../../api'; + +export const examples: DocExamples = [ + example( + 'Create a tuple value node from value nodes', + code( + 'typescript', + ` +const node = tupleValueNode([stringValueNode('Alice'), numberValueNode(42)]); +`, + ), + ), +]; diff --git a/src/v1/nodes/valueNodes/TupleValueNode.ts b/src/v1/nodes/valueNodes/TupleValueNode.ts index fdc9a455..14ba1599 100644 --- a/src/v1/nodes/valueNodes/TupleValueNode.ts +++ b/src/v1/nodes/valueNodes/TupleValueNode.ts @@ -1,4 +1,5 @@ import { array, attribute, defineNode, union } from '../../../api'; +import { examples } from './TupleValueNode.examples'; export const tupleValueNode = defineNode('tupleValueNode', { docs: ['A concrete tuple value: a fixed-length sequence of positional value nodes.'], @@ -7,4 +8,5 @@ export const tupleValueNode = defineNode('tupleValueNode', { docs: ['The positional items of the tuple, in order.'], }), ], + examples, }); diff --git a/tests/defineNode.test.ts b/tests/defineNode.test.ts index f49efccb..4c68c231 100644 --- a/tests/defineNode.test.ts +++ b/tests/defineNode.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { attribute, defineNode, optionalAttribute, string, stringIdentifier, u64 } from '../src/api'; +import { attribute, code, defineNode, example, optionalAttribute, string, stringIdentifier, u64 } from '../src/api'; describe('attribute and optionalAttribute', () => { it('produces a frozen AttributeSpec from `attribute`', () => { @@ -89,11 +89,14 @@ describe('defineNode', () => { }); it('preserves explicit examples', () => { + const ex = example('greeting', code('typescript', `const v = 'hello';`)); const n = defineNode('exampled', { attributes: [attribute('v', string())], - examples: [{ v: 'hello' }], + examples: [ex], }); - expect(n.examples).toEqual([{ v: 'hello' }]); + expect(n.examples).toEqual([ + { title: 'greeting', code: [{ language: 'typescript', content: [`const v = 'hello';`] }] }, + ]); expect(Object.isFrozen(n.examples)).toBe(true); }); }); diff --git a/tests/docs/__fixtures__/spec.ts b/tests/docs/__fixtures__/spec.ts index 37d4d271..b4d4cab1 100644 --- a/tests/docs/__fixtures__/spec.ts +++ b/tests/docs/__fixtures__/spec.ts @@ -1,11 +1,13 @@ import { address, attribute, + code, defineCategory, defineEnumeration, defineNestedUnion, defineNode, defineUnion, + example, node, optionalAttribute, string, @@ -17,6 +19,16 @@ import type { Spec } from '../../../src/api'; const numberTypeNode = defineNode('numberTypeNode', { docs: ['A number type.'], attributes: [attribute('format', string())], + examples: [ + example('u32 integers', code('typescript', `numberTypeNode('u32');`)), + example( + 'cross-language', + [code('typescript', `numberTypeNode('u8');`), code('rust', `number_type_node(U8);`)], + { + docs: ['Shown in both languages.'], + }, + ), + ], }); const typeNode = defineUnion('typeNode', { members: [node('numberTypeNode')] }); const nestedTypeNode = defineNestedUnion('nestedTypeNode', { base: union('typeNode'), wrappers: ['numberTypeNode'] }); diff --git a/tests/docs/generateDocs.test.ts b/tests/docs/generateDocs.test.ts index c95a13a5..e12ceb3d 100644 --- a/tests/docs/generateDocs.test.ts +++ b/tests/docs/generateDocs.test.ts @@ -112,3 +112,29 @@ describe('generateDocs - root index', () => { expect(rootContent()).toContain('- [HelperUnion](./HelperUnion.mdx)'); }); }); + +describe('generateDocs - examples', () => { + function content(): string { + return nodePage(generateDocs(SPEC), 'numberTypeNode').content; + } + + it('renders an Examples section after Attributes, one h3 per case', () => { + const c = content(); + expect(c.indexOf('## Attributes')).toBeLessThan(c.indexOf('## Examples')); + expect(c).toContain('### u32 integers'); + expect(c).toContain("```typescript\nnumberTypeNode('u32');\n```"); + }); + it('renders optional prose between the title and the code, matching space-joined docs', () => { + const c = content(); + expect(c.indexOf('### cross-language')).toBeLessThan(c.indexOf('Shown in both languages.')); + expect(c.indexOf('Shown in both languages.')).toBeLessThan(c.indexOf("```typescript\nnumberTypeNode('u8');")); + }); + it('stacks one fenced block per language with mapped fence tags', () => { + const c = content(); + expect(c).toContain("```typescript\nnumberTypeNode('u8');\n```"); + expect(c).toContain('```rust\nnumber_type_node(U8);\n```'); + }); + it('omits the whole section for a node carrying no examples', () => { + expect(nodePage(generateDocs(SPEC), 'programNode').content).not.toContain('## Examples'); + }); +}); diff --git a/tests/docs/renderPages.test.ts b/tests/docs/renderPages.test.ts index 53f13815..a322c4db 100644 --- a/tests/docs/renderPages.test.ts +++ b/tests/docs/renderPages.test.ts @@ -56,6 +56,46 @@ describe('renderNodePage', () => { }); }); +describe('renderNodePage examples', () => { + /** A node carrying one example with both a TypeScript and a Rust code block. */ + const node: NodeSpec = { + kind: 'amountTypeNode', + attributes: [], + examples: [ + { + title: 'a u32 USD amount', + code: [ + { language: 'typescript', content: ["amountTypeNode(numberTypeNode('u32'), 2, 'USD');"] }, + { language: 'rust', content: ['amount_type_node(number_type_node(U32), 2, "USD");'] }, + ], + }, + ], + }; + + it('renders every code block the example carries, in every language', () => { + const page = renderNodePage(node, makeCtx()); + + expect(page.content).toContain('## Examples'); + expect(page.content).toContain('### a u32 USD amount'); + expect(page.content).toContain("amountTypeNode(numberTypeNode('u32'), 2, 'USD');"); + expect(page.content).toContain('amount_type_node(number_type_node(U32), 2, "USD");'); + }); + + it('omits an example that carries no code block, rather than emitting a bare heading', () => { + const blockLessNode: NodeSpec = { + kind: 'blockLessNode', + attributes: [], + examples: [{ title: 'no snippet', code: [] }], + }; + + const page = renderNodePage(blockLessNode, makeCtx()); + + // the only example renders nothing -> the whole Examples section is dropped + expect(page.content).not.toContain('## Examples'); + expect(page.content).not.toContain('no snippet'); + }); +}); + describe('renderEnumPage', () => { it('renders a Variants list, appending the first-doc blurb only when a variant has docs', () => { const enumeration: EnumerationSpec = { diff --git a/tests/example.test.ts b/tests/example.test.ts new file mode 100644 index 00000000..ac074908 --- /dev/null +++ b/tests/example.test.ts @@ -0,0 +1,71 @@ +import { describe, expect, it } from 'vitest'; + +import { code, example } from '../src/api'; + +describe('examples - dedent', () => { + it('strips common indentation and preserves relative indent', () => { + const block = code( + 'typescript', + ` + foo(); + bar(); + `, + ); + expect(block.content).toEqual(['foo();', ' bar();']); + }); + + it('preserves internal blank lines as empty entries', () => { + const block = code( + 'typescript', + ` + a(); + + b(); + `, + ); + expect(block.content).toEqual(['a();', '', 'b();']); + }); + + it('trims a leading newline and trailing whitespace to a single line', () => { + const block = code( + 'typescript', + ` + only(); + `, + ); + expect(block.content).toEqual(['only();']); + }); + + it('handles a single-line snippet with no surrounding newlines', () => { + expect(code('typescript', `x();`).content).toEqual(['x();']); + }); +}); + +describe('examples - CodeBlock', () => { + it('passes the language through and freezes the block and its content', () => { + const block = code('rust', `let x = 1;`); + expect(block.language).toBe('rust'); + expect(Object.isFrozen(block)).toBe(true); + expect(Object.isFrozen(block.content)).toBe(true); + }); +}); + +describe('example', () => { + it('accepts a single code block and omits docs when not provided', () => { + const ex = example('single', code('typescript', `x();`)); + expect(ex).not.toHaveProperty('docs'); + expect(ex.code).toHaveLength(1); + expect(Object.isFrozen(ex)).toBe(true); + expect(Object.isFrozen(ex.code)).toBe(true); + }); + + it('accepts an array of code blocks in order', () => { + const ex = example('multi', [code('typescript', `ts();`), code('rust', `rs();`)]); + expect(ex.code.map(block => block.language)).toEqual(['typescript', 'rust']); + }); + + it('carries docs when provided', () => { + const ex = example('with docs', code('typescript', `x();`), { docs: ['A note.'] }); + expect(ex.docs).toEqual(['A note.']); + }); +}); diff --git a/v1/docs/AccountNode.mdx b/v1/docs/AccountNode.mdx index adc32367..40a1b5aa 100644 --- a/v1/docs/AccountNode.mdx +++ b/v1/docs/AccountNode.mdx @@ -20,3 +20,44 @@ An on-chain account: its name, data structure, optional fixed size, optional PDA | `data` | [`NestedTypeNode`](./typeNodes/NestedTypeNode.mdx)\<[`StructTypeNode`](./typeNodes/StructTypeNode.mdx)> | The struct describing the account data. | | `pda` | [`PdaLinkNode`](./linkNodes/PdaLinkNode.mdx) _(optional)_ | A link to the PDA the account is derived from, if applicable. | | `discriminators` | [`DiscriminatorNode`](./discriminatorNodes/DiscriminatorNode.mdx)[] _(optional)_ | Discriminators that distinguish this account from others in the program. | + +## Examples + +### A fixed-size account + +```typescript +const node = accountNode({ + name: 'token', + data: structTypeNode([ + structFieldTypeNode({ name: 'mint', type: publicKeyTypeNode() }), + structFieldTypeNode({ name: 'owner', type: publicKeyTypeNode() }), + structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') }), + ]), + discriminators: [sizeDiscriminatorNode(72)], + size: 72, +}); +``` + +### An account with a linked PDA + +```typescript +programNode({ + name: 'myProgram', + accounts: [ + accountNode({ + name: 'token', + data: structTypeNode([structFieldTypeNode({ name: 'authority', type: publicKeyTypeNode() })]), + pda: pdaLinkNode('myPda'), + }), + ], + pdas: [ + pdaNode({ + name: 'myPda', + seeds: [ + constantPdaSeedNodeFromString('utf8', 'token'), + variablePdaSeedNode('authority', publicKeyTypeNode()), + ], + }), + ], +}); +``` diff --git a/v1/docs/ConstantNode.mdx b/v1/docs/ConstantNode.mdx index bb47fbb3..76b78003 100644 --- a/v1/docs/ConstantNode.mdx +++ b/v1/docs/ConstantNode.mdx @@ -18,3 +18,25 @@ A named constant exposed by the program: a typed value associated with a name. | --------- | ----------------------------------------- | ----------------------------------- | | `type` | [`TypeNode`](./typeNodes/TypeNode.mdx) | The type of the constant. | | `value` | [`ValueNode`](./valueNodes/ValueNode.mdx) | The concrete value of the constant. | + +## Examples + +### Numeric Constant + +```typescript +const node = constantNode('maxSize', numberTypeNode('u32'), numberValueNode(100)); +``` + +### Bytes Constant + +```typescript +const node = constantNode('seedPrefix', bytesTypeNode(), bytesValueNode('base16', '74657374')); +``` + +### With Documentation + +```typescript +const node = constantNode('maxItems', numberTypeNode('u64'), numberValueNode(1000), [ + 'The maximum number of items allowed.', +]); +``` diff --git a/v1/docs/DefinedTypeNode.mdx b/v1/docs/DefinedTypeNode.mdx index e0288da2..286d9104 100644 --- a/v1/docs/DefinedTypeNode.mdx +++ b/v1/docs/DefinedTypeNode.mdx @@ -17,3 +17,18 @@ A reusable named type that can be referenced by `definedTypeLinkNode` from elsew | Attribute | Type | Description | | --------- | -------------------------------------- | -------------------- | | `type` | [`TypeNode`](./typeNodes/TypeNode.mdx) | The type definition. | + +## Examples + +### Create a defined type node from an input object + +```typescript +const node = definedTypeNode({ + name: 'person', + docs: ['This type describes a Person.'], + type: structTypeNode([ + structFieldTypeNode({ name: 'name', type: stringTypeNode('utf8') }), + structFieldTypeNode({ name: 'age', type: numberTypeNode('u8') }), + ]), +}); +``` diff --git a/v1/docs/ErrorNode.mdx b/v1/docs/ErrorNode.mdx index 8392d6b4..8924b48a 100644 --- a/v1/docs/ErrorNode.mdx +++ b/v1/docs/ErrorNode.mdx @@ -13,3 +13,15 @@ A program error — a numeric code paired with a name and human-readable message | `code` | `u32` | The numeric error code returned by the program. | | `message` | `string` | A human-readable description of the error. | | `docs` | `string[]` _(optional)_ | Markdown documentation for the error. | + +## Examples + +### Create an error node from an input object + +```typescript +const node = errorNode({ + name: 'invalidAmountArgument', + code: 1, + message: 'The amount argument is invalid.', +}); +``` diff --git a/v1/docs/EventNode.mdx b/v1/docs/EventNode.mdx index 61d85f01..c7f6cd94 100644 --- a/v1/docs/EventNode.mdx +++ b/v1/docs/EventNode.mdx @@ -18,3 +18,33 @@ A program event: its data shape and optional discriminators used to identify it | ---------------- | -------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | `data` | [`TypeNode`](./typeNodes/TypeNode.mdx) | The type describing the event payload. | | `discriminators` | [`DiscriminatorNode`](./discriminatorNodes/DiscriminatorNode.mdx)[] _(optional)_ | Discriminators that distinguish this event from others. When multiple are listed, they are combined with a logical AND. | + +## Examples + +### An event with a struct payload + +```typescript +eventNode({ + name: 'transferEvent', + data: structTypeNode([ + structFieldTypeNode({ name: 'authority', type: publicKeyTypeNode() }), + structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') }), + ]), +}); +``` + +### An event with a hidden prefix discriminator + +```typescript +eventNode({ + name: 'transferEvent', + data: hiddenPrefixTypeNode(structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') })]), [ + constantValueNode(fixedSizeTypeNode(bytesTypeNode(), 8), bytesValueNode('base16', '0102030405060708')), + ]), + discriminators: [ + constantDiscriminatorNode( + constantValueNode(fixedSizeTypeNode(bytesTypeNode(), 8), bytesValueNode('base16', '0102030405060708')), + ), + ], +}); +``` diff --git a/v1/docs/InstructionAccountNode.mdx b/v1/docs/InstructionAccountNode.mdx index c801ade6..645c0be9 100644 --- a/v1/docs/InstructionAccountNode.mdx +++ b/v1/docs/InstructionAccountNode.mdx @@ -22,3 +22,28 @@ An account participating in an instruction, with its name, signing/writability f | `defaultValue` | [`InstructionInputValueNode`](./contextualValueNodes/InstructionInputValueNode.mdx) _(optional)_ | A default value used to fill the slot when the caller does not provide one. | | `accountLink` | [`AccountLinkNode`](./linkNodes/AccountLinkNode.mdx) _(optional)_ | A reference to the account's data layout. Required for consumers (e.g. `accountFieldValueNode`) to read fields from the account. | | `display` | [`InstructionAccountDisplayNode`](./displayNodes/InstructionAccountDisplayNode.mdx) _(optional)_ | Display metadata describing how the account is presented. | + +## Examples + +### An optional account + +```typescript +instructionAccountNode({ + name: 'freezeAuthority', + isWritable: false, + isSigner: false, + isOptional: true, + docs: ['The freeze authority to set on the asset, if any.'], +}); +``` + +### An optional signer account + +```typescript +instructionAccountNode({ + name: 'owner', + isWritable: true, + isSigner: 'either', + docs: ['The owner of the asset. The owner must only sign the transaction if the asset is being updated.'], +}); +``` diff --git a/v1/docs/InstructionArgumentNode.mdx b/v1/docs/InstructionArgumentNode.mdx index fd63d9ba..b1ae71e9 100644 --- a/v1/docs/InstructionArgumentNode.mdx +++ b/v1/docs/InstructionArgumentNode.mdx @@ -20,3 +20,26 @@ A named argument of an instruction, with its type and an optional default value. | `type` | [`TypeNode`](./typeNodes/TypeNode.mdx) | The type of the argument. | | `defaultValue` | [`InstructionInputValueNode`](./contextualValueNodes/InstructionInputValueNode.mdx) _(optional)_ | A default value used when the argument is omitted by callers. | | `display` | [`StructFieldDisplayNode`](./displayNodes/StructFieldDisplayNode.mdx) _(optional)_ | Display metadata describing how the argument is presented. | + +## Examples + +### An argument with a default value + +```typescript +instructionArgumentNode({ + name: 'amount', + type: numberTypeNode('u64'), + defaultValue: numberValueNode(0), +}); +``` + +### An argument with an omitted default value + +```typescript +instructionArgumentNode({ + name: 'instructionDiscriminator', + type: numberTypeNode('u8'), + defaultValue: numberValueNode(42), + defaultValueStrategy: 'omitted', +}); +``` diff --git a/v1/docs/InstructionByteDeltaNode.mdx b/v1/docs/InstructionByteDeltaNode.mdx index 137e2b57..59c51f91 100644 --- a/v1/docs/InstructionByteDeltaNode.mdx +++ b/v1/docs/InstructionByteDeltaNode.mdx @@ -17,3 +17,23 @@ A byte-size delta applied when computing rent or buffer size — typically used | Attribute | Type | Description | | --------- | -------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | | `value` | [`InstructionByteDeltaValue`](./InstructionByteDeltaValue.mdx) | The source of the delta value — a literal number, a referenced account or argument, or a resolver. | + +## Examples + +### A byte delta that represents a new account + +```typescript +instructionByteDeltaNode(accountLinkNode('token')); +``` + +### A byte delta that represents an account deletion + +```typescript +instructionByteDeltaNode(accountLinkNode('token'), { subtract: true }); +``` + +### A byte delta that uses an argument value to increase the space of an account + +```typescript +instructionByteDeltaNode(argumentValueNode('additionalSpace'), { withHeader: false }); +``` diff --git a/v1/docs/InstructionNode.mdx b/v1/docs/InstructionNode.mdx index 2a20b811..82d55e07 100644 --- a/v1/docs/InstructionNode.mdx +++ b/v1/docs/InstructionNode.mdx @@ -28,3 +28,151 @@ A program instruction: its accounts, arguments, byte-delta hints, discriminators | `provides` | [`ProvidedNode`](./ProvidedNode.mdx)[] _(optional)_ | Named nodes exposed to consumers in the surrounding scope. | | `display` | [`InstructionDisplayNode`](./displayNodes/InstructionDisplayNode.mdx) _(optional)_ | Display metadata describing how the instruction is presented. | | `plugins` | [`PluginNode`](./PluginNode.mdx)[] _(optional)_ | Namespaced plugins with custom structured data. | + +## Examples + +### An instruction with a u8 discriminator + +```typescript +instructionNode({ + name: 'increment', + accounts: [ + instructionAccountNode({ name: 'counter', isWritable: true, isSigner: true }), + instructionAccountNode({ name: 'authority', isWritable: false, isSigner: false }), + ], + arguments: [ + instructionArgumentNode({ + name: 'discriminator', + type: numberTypeNode('u8'), + defaultValue: numberValueNode(42), + defaultValueStrategy: 'omitted', + }), + ], +}); +``` + +### An instruction that creates a new account + +```typescript +instructionNode({ + name: 'createCounter', + accounts: [ + instructionAccountNode({ name: 'counter', isWritable: true, isSigner: true }), + instructionAccountNode({ name: 'authority', isWritable: false, isSigner: false }), + ], + byteDeltas: [instructionByteDeltaNode(accountLinkNode('counter'))], +}); +``` + +### An instruction with omitted optional accounts + +```typescript +instructionNode({ + name: 'initialize', + accounts: [ + instructionAccountNode({ name: 'counter', isWritable: true, isSigner: true }), + instructionAccountNode({ name: 'authority', isWritable: false, isSigner: false }), + instructionAccountNode({ name: 'freezeAuthority', isWritable: false, isSigner: false, isOptional: true }), + ], + optionalAccountStrategy: 'omitted', +}); +``` + +### An instruction with remaining signers + +```typescript +instructionNode({ + name: 'multisigIncrement', + accounts: [instructionAccountNode({ name: 'counter', isWritable: true, isSigner: false })], + remainingAccounts: [instructionRemainingAccountsNode(argumentValueNode('authorities'), { isSigner: true })], +}); +``` + +### An instruction with nested versioned instructions + +```typescript +instructionNode({ + name: 'increment', + accounts: [ + instructionAccountNode({ name: 'counter', isWritable: true, isSigner: 'either' }), + instructionAccountNode({ name: 'authority', isWritable: false, isSigner: true }), + ], + arguments: [ + instructionArgumentNode({ name: 'version', type: numberTypeNode('u8') }), + instructionArgumentNode({ name: 'amount', type: numberTypeNode('u8') }), + ], + subInstructions: [ + instructionNode({ + name: 'incrementV1', + accounts: [instructionAccountNode({ name: 'counter', isWritable: true, isSigner: true })], + arguments: [ + instructionArgumentNode({ + name: 'version', + type: numberTypeNode('u8'), + defaultValue: numberValueNode(0), + defaultValueStrategy: 'omitted', + }), + instructionArgumentNode({ name: 'amount', type: numberTypeNode('u8') }), + ], + }), + instructionNode({ + name: 'incrementV2', + accounts: [ + instructionAccountNode({ name: 'counter', isWritable: true, isSigner: false }), + instructionAccountNode({ name: 'authority', isWritable: false, isSigner: true }), + ], + arguments: [ + instructionArgumentNode({ + name: 'version', + type: numberTypeNode('u8'), + defaultValue: numberValueNode(1), + defaultValueStrategy: 'omitted', + }), + instructionArgumentNode({ name: 'amount', type: numberTypeNode('u8') }), + ], + }), + ], +}); +``` + +### A deprecated instruction + +```typescript +instructionNode({ + name: 'oldIncrement', + status: instructionStatusNode( + 'deprecated', + 'Use the `increment` instruction instead. This will be removed in v3.0.0.', + ), + accounts: [instructionAccountNode({ name: 'counter', isWritable: true, isSigner: false })], + arguments: [instructionArgumentNode({ name: 'amount', type: numberTypeNode('u8') })], +}); +``` + +### An archived instruction + +```typescript +instructionNode({ + name: 'legacyTransfer', + status: instructionStatusNode( + 'archived', + 'This instruction was removed in v2.0.0. It is kept here for historical parsing.', + ), + accounts: [ + instructionAccountNode({ name: 'source', isWritable: true, isSigner: true }), + instructionAccountNode({ name: 'destination', isWritable: true, isSigner: false }), + ], + arguments: [instructionArgumentNode({ name: 'amount', type: numberTypeNode('u64') })], +}); +``` + +### A draft instruction + +```typescript +instructionNode({ + name: 'experimentalFeature', + status: instructionStatusNode('draft', 'This instruction is under development and may change.'), + accounts: [instructionAccountNode({ name: 'config', isWritable: true, isSigner: true })], + arguments: [], +}); +``` diff --git a/v1/docs/InstructionRemainingAccountsNode.mdx b/v1/docs/InstructionRemainingAccountsNode.mdx index 3e015d04..50ea8cc8 100644 --- a/v1/docs/InstructionRemainingAccountsNode.mdx +++ b/v1/docs/InstructionRemainingAccountsNode.mdx @@ -20,3 +20,33 @@ A "remaining accounts" slot in an instruction — a variable-length tail of acco | --------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------- | | `value` | [`InstructionRemainingAccountsValue`](./InstructionRemainingAccountsValue.mdx) | The source of the remaining-accounts list — a referenced argument or a resolver. | | `display` | [`InstructionAccountDisplayNode`](./displayNodes/InstructionAccountDisplayNode.mdx) _(optional)_ | Display metadata describing how the remaining-accounts group is presented as a whole. | + +## Examples + +### Optional remaining signers + +```typescript +instructionRemainingAccountsNode(argumentValueNode('authorities'), { + isSigner: true, + isOptional: true, +}); +``` + +### Remaining accounts that may or may not be signers + +```typescript +instructionRemainingAccountsNode(argumentValueNode('authorities'), { + isSigner: 'either', +}); +``` + +### Remaining accounts using a resolver + +```typescript +instructionRemainingAccountsNode( + resolverValueNode('resolveTransferRemainingAccounts', { + docs: ['Provide authorities as remaining accounts if and only if the asset has a multisig set up.'], + dependsOn: [argumentValueNode('hasMultisig'), argumentValueNode('authorities')], + }), +); +``` diff --git a/v1/docs/InstructionStatusNode.mdx b/v1/docs/InstructionStatusNode.mdx index 5b72f396..6c2478b8 100644 --- a/v1/docs/InstructionStatusNode.mdx +++ b/v1/docs/InstructionStatusNode.mdx @@ -16,3 +16,59 @@ The lifecycle stage of an instruction (draft, live, deprecated, archived) with a | Attribute | Type | Description | | ----------- | ---------------------------------------------------------------- | -------------------- | | `lifecycle` | [`InstructionLifecycle`](./sharedNodes/InstructionLifecycle.mdx) | The lifecycle stage. | + +## Examples + +### A live instruction (no status needed) + +```typescript +instructionNode({ + name: 'transfer', + accounts: [...], + arguments: [...], +}); +``` + +### A deprecated instruction + +```typescript +instructionNode({ + name: 'oldTransfer', + status: instructionStatusNode('deprecated', 'Use the `transfer` instruction instead. This will be removed in v3.0.0.'), + accounts: [...], + arguments: [...], +}); +``` + +### An archived instruction + +```typescript +instructionNode({ + name: 'legacyTransfer', + status: instructionStatusNode('archived', 'This instruction was removed in v2.0.0. It is kept here for historical parsing.'), + accounts: [...], + arguments: [...], +}); +``` + +### A draft instruction + +```typescript +instructionNode({ + name: 'experimentalFeature', + status: instructionStatusNode('draft', 'This instruction is under development and may change.'), + accounts: [...], + arguments: [...], +}); +``` + +### Status without a message + +```typescript +instructionNode({ + name: 'someInstruction', + status: instructionStatusNode('deprecated'), + accounts: [...], + arguments: [...], +}); +``` diff --git a/v1/docs/PdaNode.mdx b/v1/docs/PdaNode.mdx index 5ccdba02..9377ba6f 100644 --- a/v1/docs/PdaNode.mdx +++ b/v1/docs/PdaNode.mdx @@ -18,3 +18,28 @@ A program-derived address: its name, optional program ID override, and the seeds | Attribute | Type | Description | | --------- | ------------------------------------------------- | ------------------------------------------- | | `seeds` | [`PdaSeedNode`](./pdaSeedNodes/PdaSeedNode.mdx)[] | The seeds used to derive the PDA, in order. | + +## Examples + +### A PDA with constant and variable seeds + +```typescript +pdaNode({ + name: 'ticket', + seeds: [ + constantPdaSeedNodeFromString('utf8', 'raffles'), + variablePdaSeedNode('raffle', publicKeyTypeNode()), + constantPdaSeedNodeFromString('utf8', 'tickets'), + variablePdaSeedNode('ticketNumber', numberTypeNode('u32')), + ], +}); +``` + +### A PDA with no seeds + +```typescript +pdaNode({ + name: 'seedlessPda', + seeds: [], +}); +``` diff --git a/v1/docs/ProgramNode.mdx b/v1/docs/ProgramNode.mdx index d8041d88..92c07f73 100644 --- a/v1/docs/ProgramNode.mdx +++ b/v1/docs/ProgramNode.mdx @@ -26,3 +26,21 @@ A Solana program: its identity, version, accounts, instructions, defined types, | `events` | [`EventNode`](./EventNode.mdx)[] | The events emitted by the program. | | `errors` | [`ErrorNode`](./ErrorNode.mdx)[] | The errors returned by the program. | | `constants` | [`ConstantNode`](./ConstantNode.mdx)[] | The constants exposed by the program. | + +## Examples + +### Create a program node from an input object + +```typescript +const node = programNode({ + name: 'counter', + publicKey: '7ovtg4pFqjQdSwFAUCu8gTnh5thZHzAyJFXy3Ssnj3yK', + version: '1.42.6', + accounts: [], + instructions: [], + definedTypes: [], + pdas: [], + events: [], + errors: [], +}); +``` diff --git a/v1/docs/RootNode.mdx b/v1/docs/RootNode.mdx index 1266e3e6..57a03255 100644 --- a/v1/docs/RootNode.mdx +++ b/v1/docs/RootNode.mdx @@ -18,3 +18,32 @@ The root of a Codama IDL document. Pairs a primary program with any number of ad | -------------------- | ------------------------------------ | ------------------------------------------------------ | | `program` | [`ProgramNode`](./ProgramNode.mdx) | The primary program described by the document. | | `additionalPrograms` | [`ProgramNode`](./ProgramNode.mdx)[] | Additional programs referenced by the primary program. | + +## Examples + +### A root node with a single program + +```typescript +const node = rootNode( + programNode({ + name: 'counter', + publicKey: '2R3Ui2TVUUCyGcZdopxJauk8ZBzgAaHHZCVUhm5ifPaC', + version: '1.0.0', + accounts: [ + accountNode({ + name: 'counter', + data: structTypeNode([ + structFieldTypeNode({ name: 'authority', type: publicKeyTypeNode() }), + structFieldTypeNode({ name: 'value', type: numberTypeNode('u32') }), + ]), + }), + ], + instructions: [ + instructionNode({ name: 'create' /* ... */ }), + instructionNode({ name: 'increment' /* ... */ }), + instructionNode({ name: 'transferAuthority' /* ... */ }), + instructionNode({ name: 'delete' /* ... */ }), + ], + }), +); +``` diff --git a/v1/docs/contextualValueNodes/AccountBumpValueNode.mdx b/v1/docs/contextualValueNodes/AccountBumpValueNode.mdx index 3ba1d1cd..e452bd30 100644 --- a/v1/docs/contextualValueNodes/AccountBumpValueNode.mdx +++ b/v1/docs/contextualValueNodes/AccountBumpValueNode.mdx @@ -10,3 +10,35 @@ Refers to the bump seed of a named PDA-derived account in the surrounding instru | --------- | ------------------------ | ------------------------------------------------------ | | `kind` | `"accountBumpValueNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the account whose bump seed is referenced. | + +## Examples + +### Create an account bump value node from an account name + +```typescript +const node = accountBumpValueNode('associatedTokenAccount'); +``` + +### An instruction argument defaulting to the bump derivation of an instruction account + +```typescript +instructionNode({ + name: 'transfer', + accounts: [ + instructionAccountNode({ + name: 'associatedTokenAccount', + isSigner: false, + isWritable: true, + }), + // ... + ], + arguments: [ + instructionArgumentNode({ + name: 'bump', + type: numberTypeNode('u8'), + defaultValue: accountBumpValueNode('associatedTokenAccount'), + }), + // ... + ], +}); +``` diff --git a/v1/docs/contextualValueNodes/AccountValueNode.mdx b/v1/docs/contextualValueNodes/AccountValueNode.mdx index 6f569aed..f86cba41 100644 --- a/v1/docs/contextualValueNodes/AccountValueNode.mdx +++ b/v1/docs/contextualValueNodes/AccountValueNode.mdx @@ -10,3 +10,33 @@ Refers to a named account in the surrounding instruction. | --------- | -------------------- | ----------------------------------- | | `kind` | `"accountValueNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the referenced account. | + +## Examples + +### Create an account value node from an account name + +```typescript +const node = accountValueNode('mint'); +``` + +### An instruction account defaulting to another account + +```typescript +instructionNode({ + name: 'mint', + accounts: [ + instructionAccountNode({ + name: 'payer', + isSigner: true, + isWritable: false, + }), + instructionAccountNode({ + name: 'authority', + isSigner: false, + isWritable: true, + defaultValue: accountValueNode('payer'), + }), + // ... + ], +}); +``` diff --git a/v1/docs/contextualValueNodes/ArgumentValueNode.mdx b/v1/docs/contextualValueNodes/ArgumentValueNode.mdx index d7f0deb7..df1f18a4 100644 --- a/v1/docs/contextualValueNodes/ArgumentValueNode.mdx +++ b/v1/docs/contextualValueNodes/ArgumentValueNode.mdx @@ -10,3 +10,31 @@ Refers to a named argument of the surrounding instruction. | --------- | --------------------- | ------------------------------------ | | `kind` | `"argumentValueNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the referenced argument. | + +## Examples + +### Create an argument value node from an argument name + +```typescript +const node = argumentValueNode('amount'); +``` + +### An instruction argument defaulting to another argument + +```typescript +instructionNode({ + name: 'mint', + arguments: [ + instructionArgumentNode({ + name: 'amount', + type: numberTypeNode('u64'), + }), + instructionArgumentNode({ + name: 'amountToDelegate', + type: numberTypeNode('u64'), + defaultValue: argumentValueNode('amount'), + }), + // ... + ], +}); +``` diff --git a/v1/docs/contextualValueNodes/ConditionalValueNode.mdx b/v1/docs/contextualValueNodes/ConditionalValueNode.mdx index 2314fc3f..4f85fd27 100644 --- a/v1/docs/contextualValueNodes/ConditionalValueNode.mdx +++ b/v1/docs/contextualValueNodes/ConditionalValueNode.mdx @@ -18,3 +18,49 @@ A branching contextual value. The condition resolves to a value at instruction t | `value` | [`ValueNode`](../valueNodes/ValueNode.mdx) _(optional)_ | When present, the condition result is compared for equality against this value. | | `ifTrue` | [`InstructionInputValueNode`](./InstructionInputValueNode.mdx) _(optional)_ | The value used when the condition resolves truthy (or matches `value`). | | `ifFalse` | [`InstructionInputValueNode`](./InstructionInputValueNode.mdx) _(optional)_ | The value used when the condition resolves falsy (or does not match `value`). | + +## Examples + +### Create a conditional value node from an input object + +```typescript +const node = conditionalValueNode({ + condition: argumentValueNode('amount'), + value: numberValueNode(0), + ifTrue: accountValueNode('mint'), + ifFalse: programIdValueNode(), +}); +``` + +### An instruction account that defaults to another account if a condition is met + +```typescript +instructionNode({ + name: 'transfer', + accounts: [ + instructionAccountNode({ + name: 'source', + isSigner: false, + isWritable: true, + }), + instructionAccountNode({ + name: 'destination', + isSigner: false, + isWritable: true, + isOptional: true, + defaultValue: conditionalValueNode({ + condition: argumentValueNode('amount'), + value: numberValueNode(0), + ifTrue: accountValueNode('source'), + }), + }), + // ... + ], + arguments: [ + instructionArgumentNode({ + name: 'amount', + type: numberTypeNode('u64'), + }), + ], +}); +``` diff --git a/v1/docs/contextualValueNodes/IdentityValueNode.mdx b/v1/docs/contextualValueNodes/IdentityValueNode.mdx index f9d7c0c1..c3687da4 100644 --- a/v1/docs/contextualValueNodes/IdentityValueNode.mdx +++ b/v1/docs/contextualValueNodes/IdentityValueNode.mdx @@ -9,3 +9,28 @@ Refers to the wallet identity providing the instruction context. | Attribute | Type | Description | | --------- | --------------------- | ----------------------- | | `kind` | `"identityValueNode"` | The node discriminator. | + +## Examples + +### Create an identity value node + +```typescript +const node = identityValueNode(); +``` + +### An instruction account defaulting to the identity value + +```typescript +instructionNode({ + name: 'transfer', + accounts: [ + instructionAccountNode({ + name: 'authority', + isSigner: true, + isWritable: false, + defaultValue: identityValueNode(), + }), + // ... + ], +}); +``` diff --git a/v1/docs/contextualValueNodes/PayerValueNode.mdx b/v1/docs/contextualValueNodes/PayerValueNode.mdx index 31a180e4..d730d858 100644 --- a/v1/docs/contextualValueNodes/PayerValueNode.mdx +++ b/v1/docs/contextualValueNodes/PayerValueNode.mdx @@ -9,3 +9,28 @@ Refers to the wallet paying for the surrounding transaction. | Attribute | Type | Description | | --------- | ------------------ | ----------------------- | | `kind` | `"payerValueNode"` | The node discriminator. | + +## Examples + +### Create a payer value node + +```typescript +const node = payerValueNode(); +``` + +### An instruction account defaulting to the payer value + +```typescript +instructionNode({ + name: 'transfer', + accounts: [ + instructionAccountNode({ + name: 'payer', + isSigner: true, + isWritable: false, + defaultValue: payerValueNode(), + }), + // ... + ], +}); +``` diff --git a/v1/docs/contextualValueNodes/PdaSeedValueNode.mdx b/v1/docs/contextualValueNodes/PdaSeedValueNode.mdx index b844236e..073575ae 100644 --- a/v1/docs/contextualValueNodes/PdaSeedValueNode.mdx +++ b/v1/docs/contextualValueNodes/PdaSeedValueNode.mdx @@ -16,3 +16,11 @@ Pairs a PDA seed name with the value to substitute when deriving the PDA. | Attribute | Type | Description | | --------- | ---------------------------------------------- | ------------------------------------- | | `value` | [`PdaSeedValueValue`](./PdaSeedValueValue.mdx) | The value to substitute for the seed. | + +## Examples + +### Create a PDA seed value node from a name and a value + +```typescript +const node = pdaSeedValueNode('mint', accountValueNode('mint')); +``` diff --git a/v1/docs/contextualValueNodes/PdaValueNode.mdx b/v1/docs/contextualValueNodes/PdaValueNode.mdx index 3497f6cc..dcc4ecdc 100644 --- a/v1/docs/contextualValueNodes/PdaValueNode.mdx +++ b/v1/docs/contextualValueNodes/PdaValueNode.mdx @@ -17,3 +17,41 @@ Resolves to a PDA derived from a list of seed values. | `pda` | [`PdaValuePda`](./PdaValuePda.mdx) | The PDA being derived — either a link to a defined PDA or an inline `pdaNode`. | | `seeds` | [`PdaSeedValueNode`](./PdaSeedValueNode.mdx)[] | The seed values used to derive the PDA, paired with their seed names. | | `programId` | [`PdaValueProgramId`](./PdaValueProgramId.mdx) _(optional)_ | The program ID used to derive the PDA. When omitted, the PDA’s declared program is used. | + +## Examples + +### Create a PDA value node from a PDA definition and seed values + +```typescript +const node = pdaValueNode('associatedToken', [ + pdaSeedValueNode('mint', publicKeyValueNode('G345gmp34svbGxyXuCvKVVHDbqJQ66y65vVrx7m7FmBE')), + pdaSeedValueNode('owner', publicKeyValueNode('Nzgr9bYfMRq5768bHfXsXoPTnLWAXgQNosRBxK63jRH')), +]); +``` + +### A PDA value whose seeds point to other accounts + +```typescript +pdaValueNode('associatedToken', [ + pdaSeedValueNode('mint', accountValueNode('mint')), + pdaSeedValueNode('owner', accountValueNode('authority')), +]); +``` + +### A PDA value with an inlined PDA definition + +```typescript +const inlinedPdaNode = pdaNode({ + name: 'associatedToken', + seeds: [ + variablePdaSeedNode('mint', publicKeyTypeNode()), + constantPdaSeedNode(publicKeyTypeNode(), publicKeyValueNode('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA')), + variablePdaSeedNode('owner', publicKeyTypeNode()), + ], +}); + +pdaValueNode(inlinedPdaNode, [ + pdaSeedValueNode('mint', accountValueNode('mint')), + pdaSeedValueNode('owner', accountValueNode('authority')), +]); +``` diff --git a/v1/docs/contextualValueNodes/ProgramIdValueNode.mdx b/v1/docs/contextualValueNodes/ProgramIdValueNode.mdx index ab323ca5..1378d312 100644 --- a/v1/docs/contextualValueNodes/ProgramIdValueNode.mdx +++ b/v1/docs/contextualValueNodes/ProgramIdValueNode.mdx @@ -9,3 +9,11 @@ Refers to the program ID of the surrounding instruction. | Attribute | Type | Description | | --------- | ---------------------- | ----------------------- | | `kind` | `"programIdValueNode"` | The node discriminator. | + +## Examples + +### Create a program id value node + +```typescript +const node = programIdValueNode(); +``` diff --git a/v1/docs/contextualValueNodes/ResolverValueNode.mdx b/v1/docs/contextualValueNodes/ResolverValueNode.mdx index df653e8b..b733c4cd 100644 --- a/v1/docs/contextualValueNodes/ResolverValueNode.mdx +++ b/v1/docs/contextualValueNodes/ResolverValueNode.mdx @@ -17,3 +17,18 @@ A custom resolver: a named function provided by the consumer that produces a val | Attribute | Type | Description | | ----------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | | `dependsOn` | [`ResolverDependency`](./ResolverDependency.mdx)[] _(optional)_ | The accounts and arguments the resolver depends on. Used by clients to ensure the dependencies are resolved first. | + +## Examples + +### Create a resolver value node from a name and options + +```typescript +const node = resolverValueNode('resolveCustomTokenProgram', { + docs: [ + 'If the mint account has more than 0 decimals and the ', + 'delegated amount is greater than zero, then we use our ', + 'own custom token program. Otherwise, we use Token 2022.', + ], + dependsOn: [accountValueNode('mint'), argumentValueNode('delegatedAmount')], +}); +``` diff --git a/v1/docs/countNodes/FixedCountNode.mdx b/v1/docs/countNodes/FixedCountNode.mdx index 8075e1e0..8a599152 100644 --- a/v1/docs/countNodes/FixedCountNode.mdx +++ b/v1/docs/countNodes/FixedCountNode.mdx @@ -10,3 +10,17 @@ A count strategy that fixes the number of items at a constant value. | --------- | ------------------ | -------------------------- | | `kind` | `"fixedCountNode"` | The node discriminator. | | `value` | `u64` | The fixed number of items. | + +## Examples + +### Create a fixed count node from a number + +```typescript +const node = fixedCountNode(42); +``` + +### An array of three public keys + +```typescript +arrayTypeNode(publicKeyTypeNode(), fixedCountNode(3)); +``` diff --git a/v1/docs/countNodes/PrefixedCountNode.mdx b/v1/docs/countNodes/PrefixedCountNode.mdx index 2b85bc0e..aadb71b0 100644 --- a/v1/docs/countNodes/PrefixedCountNode.mdx +++ b/v1/docs/countNodes/PrefixedCountNode.mdx @@ -15,3 +15,17 @@ A count strategy where the number of items is read from a numeric prefix. | Attribute | Type | Description | | --------- | --------------------------------------------------------------------------------------------------------- | ------------------------------------------ | | `prefix` | [`NestedTypeNode`](../typeNodes/NestedTypeNode.mdx)\<[`NumberTypeNode`](../typeNodes/NumberTypeNode.mdx)> | The numeric type used as the count prefix. | + +## Examples + +### Create a prefixed count node from a number node + +```typescript +const node = prefixedCountNode(numberTypeNode('u32')); +``` + +### A variable array of public keys prefixed with a u32 + +```typescript +arrayTypeNode(publicKeyTypeNode(), prefixedCountNode(numberTypeNode('u32'))); +``` diff --git a/v1/docs/countNodes/RemainderCountNode.mdx b/v1/docs/countNodes/RemainderCountNode.mdx index 4c07c738..45543edf 100644 --- a/v1/docs/countNodes/RemainderCountNode.mdx +++ b/v1/docs/countNodes/RemainderCountNode.mdx @@ -9,3 +9,17 @@ A count strategy where items are read until the buffer is exhausted. | Attribute | Type | Description | | --------- | ---------------------- | ----------------------- | | `kind` | `"remainderCountNode"` | The node discriminator. | + +## Examples + +### Create a remainder count node + +```typescript +const node = remainderCountNode(); +``` + +### A remainder array of public keys + +```typescript +arrayTypeNode(publicKeyTypeNode(), remainderCountNode()); +``` diff --git a/v1/docs/discriminatorNodes/ConstantDiscriminatorNode.mdx b/v1/docs/discriminatorNodes/ConstantDiscriminatorNode.mdx index dc19f92a..4709c9fc 100644 --- a/v1/docs/discriminatorNodes/ConstantDiscriminatorNode.mdx +++ b/v1/docs/discriminatorNodes/ConstantDiscriminatorNode.mdx @@ -16,3 +16,31 @@ Identifies a node by a constant value at a known byte offset (e.g. a magic heade | Attribute | Type | Description | | ---------- | ---------------------------------------------------------- | ------------------------------------------ | | `constant` | [`ConstantValueNode`](../valueNodes/ConstantValueNode.mdx) | The constant value expected at the offset. | + +## Examples + +### Create a constant discriminator node from a constant value and an optional offset + +```typescript +const node = constantDiscriminatorNode(constantValueNode(stringTypeNode('utf8'), stringValueNode('Hello')), 64); +``` + +### An account distinguished by a u32 number equal to 42 at offset 0 + +```typescript +accountNode({ + discriminators: [constantDiscriminatorNode(constantValueNode(numberTypeNode('u32'), numberValueNode(42)))], + // ... +}); +``` + +### An instruction distinguished by an 8-byte hash at offset 0 + +```typescript +instructionNode({ + discriminators: [ + constantDiscriminatorNode(constantValueNode(bytesTypeNode(), bytesValueNode('base16', '0011223344556677'))), + ], + // ... +}); +``` diff --git a/v1/docs/discriminatorNodes/FieldDiscriminatorNode.mdx b/v1/docs/discriminatorNodes/FieldDiscriminatorNode.mdx index e80eeee5..567bd77c 100644 --- a/v1/docs/discriminatorNodes/FieldDiscriminatorNode.mdx +++ b/v1/docs/discriminatorNodes/FieldDiscriminatorNode.mdx @@ -11,3 +11,47 @@ Identifies a node by the value of a named field at a known byte offset. | `kind` | `"fieldDiscriminatorNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the discriminating field. | | `offset` | `u64` | The byte offset of the field. | + +## Examples + +### Create a field discriminator node from a field name and an optional offset + +```typescript +const node = fieldDiscriminatorNode('accountState', 64); +``` + +### An account distinguished by a u32 field at offset 0 + +```typescript +accountNode({ + data: structTypeNode([ + structFieldTypeNode({ + name: 'discriminator', + type: numberTypeNode('u32'), + defaultValue: numberValueNode(42), + defaultValueStrategy: 'omitted', + }), + // ... + ]), + discriminators: [fieldDiscriminatorNode('discriminator')], + // ... +}); +``` + +### An instruction distinguished by an 8-byte argument at offset 0 + +```typescript +instructionNode({ + arguments: [ + instructionArgumentNode({ + name: 'discriminator', + type: fixedSizeTypeNode(bytesTypeNode(), 8), + defaultValue: bytesValueNode('base16', '0011223344556677'), + defaultValueStrategy: 'omitted', + }), + // ... + ], + discriminators: [fieldDiscriminatorNode('discriminator')], + // ... +}); +``` diff --git a/v1/docs/discriminatorNodes/SizeDiscriminatorNode.mdx b/v1/docs/discriminatorNodes/SizeDiscriminatorNode.mdx index 23fb2dcd..b02691fa 100644 --- a/v1/docs/discriminatorNodes/SizeDiscriminatorNode.mdx +++ b/v1/docs/discriminatorNodes/SizeDiscriminatorNode.mdx @@ -10,3 +10,29 @@ Identifies a node by its expected total byte size. | --------- | ------------------------- | ----------------------- | | `kind` | `"sizeDiscriminatorNode"` | The node discriminator. | | `size` | `u64` | The expected byte size. | + +## Examples + +### Create a size discriminator node from a size + +```typescript +const node = sizeDiscriminatorNode(165); +``` + +### An account distinguished by its size being equal to 42 + +```typescript +accountNode({ + discriminators: [sizeDiscriminatorNode(42)], + // ... +}); +``` + +### An instruction distinguished by its size being equal to 42 + +```typescript +instructionNode({ + discriminators: [sizeDiscriminatorNode(42)], + // ... +}); +``` diff --git a/v1/docs/displayNodes/AmountNumberDisplayNode.mdx b/v1/docs/displayNodes/AmountNumberDisplayNode.mdx index c6381b53..67741cd6 100644 --- a/v1/docs/displayNodes/AmountNumberDisplayNode.mdx +++ b/v1/docs/displayNodes/AmountNumberDisplayNode.mdx @@ -16,3 +16,28 @@ Display metadata that presents a number as a scaled amount with an optional unit | ---------- | --------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `decimals` | [`InjectableNumberValueNode`](../valueNodes/InjectableNumberValueNode.mdx) _(optional)_ | How many decimal places scale the underlying integer. Resolved as a number value: either a literal `numberValueNode` or a key resolved from a surrounding provider. | | `unit` | [`InjectableStringValueNode`](../valueNodes/InjectableStringValueNode.mdx) _(optional)_ | A label appended after the scaled value (e.g. `"USDC"`, `"%"`, `"bps"`). Resolved as a string value: either a literal `stringValueNode` or a key resolved from a surrounding provider. | + +## Examples + +### A fixed 9-decimal SOL amount + +```typescript +numberTypeNode('u64', 'le', { + display: amountNumberDisplayNode({ decimals: numberValueNode(9), unit: stringValueNode('SOL') }), +}); + +// 1_100_000_000 => "1.1 SOL" +``` + +### Decimals and unit injected from surrounding account state + +```typescript +numberTypeNode('u64', 'le', { + display: amountNumberDisplayNode({ + decimals: injectedValueNode({ key: 'decimals' }), + unit: injectedValueNode({ key: 'symbol' }), + }), +}); + +// 1_500_000 with injected decimals 6 and symbol "USDC" => "1.5 USDC" +``` diff --git a/v1/docs/displayNodes/DateTimeNumberDisplayNode.mdx b/v1/docs/displayNodes/DateTimeNumberDisplayNode.mdx index 9fe2a227..939446a3 100644 --- a/v1/docs/displayNodes/DateTimeNumberDisplayNode.mdx +++ b/v1/docs/displayNodes/DateTimeNumberDisplayNode.mdx @@ -10,3 +10,21 @@ Display metadata that presents a number as a point in time. The underlying value | ---------------- | ----------------------------- | ---------------------------------------------------------------------------------- | | `kind` | `"dateTimeNumberDisplayNode"` | The node discriminator. | | `ticksPerSecond` | `u64` _(optional)_ | How many ticks make one second. Defaults to `1` (the value is already in seconds). | + +## Examples + +### A Unix timestamp already in seconds + +```typescript +numberTypeNode('i64', 'le', { display: dateTimeNumberDisplayNode({}) }); + +// 1_761_365_183 => "2025-10-25T04:06:23.000Z" +``` + +### A millisecond timestamp scaled back to seconds + +```typescript +numberTypeNode('i64', 'le', { display: dateTimeNumberDisplayNode({ ticksPerSecond: 1000 }) }); + +// 1_761_365_183_000 => "2025-10-25T04:06:23.000Z" +``` diff --git a/v1/docs/displayNodes/DurationNumberDisplayNode.mdx b/v1/docs/displayNodes/DurationNumberDisplayNode.mdx index 6e463049..2b50675b 100644 --- a/v1/docs/displayNodes/DurationNumberDisplayNode.mdx +++ b/v1/docs/displayNodes/DurationNumberDisplayNode.mdx @@ -10,3 +10,21 @@ Display metadata that presents a number as an elapsed duration. The underlying v | ---------------- | ----------------------------- | ---------------------------------------------------------------------------------- | | `kind` | `"durationNumberDisplayNode"` | The node discriminator. | | `ticksPerSecond` | `u64` _(optional)_ | How many ticks make one second. Defaults to `1` (the value is already in seconds). | + +## Examples + +### A duration already in seconds + +```typescript +numberTypeNode('u32', 'le', { display: durationNumberDisplayNode({}) }); + +// 3600 => "01:00:00" +``` + +### A duration in milliseconds scaled back to seconds + +```typescript +numberTypeNode('u64', 'le', { display: durationNumberDisplayNode({ ticksPerSecond: 1000 }) }); + +// 90_000 => "00:01:30" +``` diff --git a/v1/docs/displayNodes/EnumVariantDisplayNode.mdx b/v1/docs/displayNodes/EnumVariantDisplayNode.mdx index 75c75760..e1c521fe 100644 --- a/v1/docs/displayNodes/EnumVariantDisplayNode.mdx +++ b/v1/docs/displayNodes/EnumVariantDisplayNode.mdx @@ -11,3 +11,27 @@ Display metadata for an enum variant: its label and whether to hide its inner pa | `kind` | `"enumVariantDisplayNode"` | The node discriminator. | | `label` | `string` _(optional)_ | An override label shown for the variant (e.g. `"Buy"`). | | `skipInnerData` | `boolean` _(optional)_ | When `true`, the variant's payload is hidden — only the label is rendered. | + +## Examples + +### Relabelling a struct variant + +```typescript +enumStructVariantTypeNode( + 'buy', + structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') })]), + undefined, + { display: enumVariantDisplayNode({ label: 'Buy' }) }, +); +``` + +### Hiding a tuple payload so only the label is shown + +```typescript +enumTupleVariantTypeNode( + 'increment', + tupleTypeNode([numberTypeNode('u64')]), + undefined, + { display: enumVariantDisplayNode({ label: 'Increment', skipInnerData: true }) }, +); +``` diff --git a/v1/docs/displayNodes/InstructionAccountDisplayNode.mdx b/v1/docs/displayNodes/InstructionAccountDisplayNode.mdx index 35ce5187..a43c0f4f 100644 --- a/v1/docs/displayNodes/InstructionAccountDisplayNode.mdx +++ b/v1/docs/displayNodes/InstructionAccountDisplayNode.mdx @@ -16,3 +16,27 @@ Display metadata for an instruction account: its label in the fallback list and | Attribute | Type | Description | | --------- | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------- | | `skip` | [`DisplaySkip`](../sharedNodes/DisplaySkip.mdx) _(optional)_ | Whether the account is shown in the fallback list. Defaults to `"never"` (always shown). | + +## Examples + +### Relabelling an account in the fallback list + +```typescript +instructionAccountNode({ + name: 'destination', + isSigner: false, + isWritable: true, + display: instructionAccountDisplayNode({ label: 'To' }), +}); +``` + +### Hiding an account once its value is surfaced elsewhere + +```typescript +instructionAccountNode({ + name: 'mint', + isSigner: false, + isWritable: false, + display: instructionAccountDisplayNode({ label: 'Token Mint', skip: 'whenInjected' }), +}); +``` diff --git a/v1/docs/displayNodes/InstructionDisplayNode.mdx b/v1/docs/displayNodes/InstructionDisplayNode.mdx index 4724ae79..fd9e7791 100644 --- a/v1/docs/displayNodes/InstructionDisplayNode.mdx +++ b/v1/docs/displayNodes/InstructionDisplayNode.mdx @@ -11,3 +11,31 @@ Display metadata for an instruction: a short intent label and an interpolated se | `kind` | `"instructionDisplayNode"` | The node discriminator. | | `intent` | `string` _(optional)_ | A short imperative label describing what the instruction does (e.g. `"Transfer"`). | | `interpolatedIntent` | `string` _(optional)_ | A sentence template that composes the instruction into prose with `${root.path}` placeholders. | + +## Examples + +### An intent label plus an interpolated sentence + +```typescript +instructionNode({ + name: 'transferChecked', + display: instructionDisplayNode({ + intent: 'Transfer', + interpolatedIntent: 'Transfer ${data.amount} to ${accounts.destination}', + }), + // ...accounts and arguments +}); + +// intent => "Transfer" +// interpolated => "Transfer 1.5 USDC to 3Wnd5…5PxJX" +``` + +### An intent label only, letting the renderer build the fallback list + +```typescript +instructionNode({ + name: 'closeAccount', + display: instructionDisplayNode({ intent: 'Close Account' }), + // ...accounts and arguments +}); +``` diff --git a/v1/docs/displayNodes/StringDisplayNode.mdx b/v1/docs/displayNodes/StringDisplayNode.mdx index 29520631..9a737c6d 100644 --- a/v1/docs/displayNodes/StringDisplayNode.mdx +++ b/v1/docs/displayNodes/StringDisplayNode.mdx @@ -11,3 +11,21 @@ Display metadata for a string value. The string's wire encoding is carried by `s | `kind` | `"stringDisplayNode"` | The node discriminator. | | `sliceStart` | `u64` _(optional)_ | The start index of the displayed slice, inclusive. Defaults to the start of the string. | | `sliceEnd` | `u64` _(optional)_ | The end index of the displayed slice, exclusive. Defaults to the end of the string. | + +## Examples + +### Displaying the whole string + +```typescript +stringTypeNode('utf8', { display: stringDisplayNode({}) }); + +// "SOLANA" => "SOLANA" +``` + +### Displaying a leading slice + +```typescript +stringTypeNode('utf8', { display: stringDisplayNode({ sliceStart: 0, sliceEnd: 3 }) }); + +// "SOLANA" => "SOL" +``` diff --git a/v1/docs/displayNodes/StructFieldDisplayNode.mdx b/v1/docs/displayNodes/StructFieldDisplayNode.mdx index 74539dec..2df927b0 100644 --- a/v1/docs/displayNodes/StructFieldDisplayNode.mdx +++ b/v1/docs/displayNodes/StructFieldDisplayNode.mdx @@ -18,3 +18,35 @@ Display metadata for a named member: its label, whether it is shown in the fallb | Attribute | Type | Description | | --------- | ------------------------------------------------------------ | --------------------------------------------------------------------------------------- | | `skip` | [`DisplaySkip`](../sharedNodes/DisplaySkip.mdx) _(optional)_ | Whether the member is shown in the fallback list. Defaults to `"never"` (always shown). | + +## Examples + +### Relabelling an instruction argument + +```typescript +instructionArgumentNode({ + name: 'amount', + type: numberTypeNode('u64'), + display: structFieldDisplayNode({ label: 'Amount' }), +}); +``` + +### Hiding a discriminator argument from the fallback list + +```typescript +instructionArgumentNode({ + name: 'discriminator', + type: numberTypeNode('u8'), + display: structFieldDisplayNode({ skip: 'always' }), +}); +``` + +### Flattening a nested struct into its parent with a label prefix + +```typescript +structFieldTypeNode({ + name: 'config', + type: definedTypeLinkNode('config'), + display: structFieldDisplayNode({ flatten: true, flattenPrefix: 'config.' }), +}); +``` diff --git a/v1/docs/linkNodes/AccountLinkNode.mdx b/v1/docs/linkNodes/AccountLinkNode.mdx index c7b4f124..f098b0b2 100644 --- a/v1/docs/linkNodes/AccountLinkNode.mdx +++ b/v1/docs/linkNodes/AccountLinkNode.mdx @@ -16,3 +16,12 @@ A reference to an account defined elsewhere — possibly in a different program. | Attribute | Type | Description | | --------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | | `program` | [`ProgramLinkNode`](./ProgramLinkNode.mdx) _(optional)_ | The program the referenced account belongs to. When omitted, the surrounding program is assumed. | + +## Examples + +### Create an account link node from an account name + +```typescript +const node = accountLinkNode('myAccount'); +const nodeFromAnotherProgram = accountLinkNode('myAccount', 'myOtherProgram'); +``` diff --git a/v1/docs/linkNodes/DefinedTypeLinkNode.mdx b/v1/docs/linkNodes/DefinedTypeLinkNode.mdx index ce0bcb6d..43df7a77 100644 --- a/v1/docs/linkNodes/DefinedTypeLinkNode.mdx +++ b/v1/docs/linkNodes/DefinedTypeLinkNode.mdx @@ -16,3 +16,12 @@ A reference to a defined type — possibly in a different program. | Attribute | Type | Description | | --------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | | `program` | [`ProgramLinkNode`](./ProgramLinkNode.mdx) _(optional)_ | The program the referenced type is defined in. When omitted, the surrounding program is assumed. | + +## Examples + +### Create a defined type link node from a type name + +```typescript +const node = definedTypeLinkNode('myDefinedType'); +const nodeFromAnotherProgram = definedTypeLinkNode('myDefinedType', 'myOtherProgram'); +``` diff --git a/v1/docs/linkNodes/InstructionAccountLinkNode.mdx b/v1/docs/linkNodes/InstructionAccountLinkNode.mdx index b5e61074..31befb2f 100644 --- a/v1/docs/linkNodes/InstructionAccountLinkNode.mdx +++ b/v1/docs/linkNodes/InstructionAccountLinkNode.mdx @@ -16,3 +16,21 @@ A reference to an account of another instruction. | Attribute | Type | Description | | ------------- | --------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | | `instruction` | [`InstructionLinkNode`](./InstructionLinkNode.mdx) _(optional)_ | The instruction the referenced account belongs to. When omitted, the surrounding instruction is assumed. | + +## Examples + +### Create an instruction account link node from an account name + +```typescript +// Links to an account in the current instruction. +const node = instructionAccountLinkNode('myAccount'); + +// Links to an account in another instruction but within the same program. +const nodeFromAnotherInstruction = instructionAccountLinkNode('myAccount', 'myOtherInstruction'); + +// Links to an account in another instruction from another program. +const nodeFromAnotherProgram = instructionAccountLinkNode( + 'myAccount', + instructionLinkNode('myOtherInstruction', 'myOtherProgram'), +); +``` diff --git a/v1/docs/linkNodes/InstructionArgumentLinkNode.mdx b/v1/docs/linkNodes/InstructionArgumentLinkNode.mdx index be3b27ee..25679bfb 100644 --- a/v1/docs/linkNodes/InstructionArgumentLinkNode.mdx +++ b/v1/docs/linkNodes/InstructionArgumentLinkNode.mdx @@ -16,3 +16,21 @@ A reference to an argument of another instruction. | Attribute | Type | Description | | ------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | | `instruction` | [`InstructionLinkNode`](./InstructionLinkNode.mdx) _(optional)_ | The instruction the referenced argument belongs to. When omitted, the surrounding instruction is assumed. | + +## Examples + +### Create an instruction argument link node from an argument name + +```typescript +// Links to an argument in the current instruction. +const node = instructionArgumentLinkNode('myArgument'); + +// Links to an argument in another instruction but within the same program. +const nodeFromAnotherInstruction = instructionArgumentLinkNode('myArgument', 'myOtherInstruction'); + +// Links to an argument in another instruction from another program. +const nodeFromAnotherProgram = instructionArgumentLinkNode( + 'myArgument', + instructionLinkNode('myOtherInstruction', 'myOtherProgram'), +); +``` diff --git a/v1/docs/linkNodes/InstructionLinkNode.mdx b/v1/docs/linkNodes/InstructionLinkNode.mdx index 37163b54..c83d37e5 100644 --- a/v1/docs/linkNodes/InstructionLinkNode.mdx +++ b/v1/docs/linkNodes/InstructionLinkNode.mdx @@ -16,3 +16,12 @@ A reference to an instruction defined elsewhere — possibly in a different prog | Attribute | Type | Description | | --------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | | `program` | [`ProgramLinkNode`](./ProgramLinkNode.mdx) _(optional)_ | The program the referenced instruction belongs to. When omitted, the surrounding program is assumed. | + +## Examples + +### Create an instruction link node from an instruction name + +```typescript +const node = instructionLinkNode('myInstruction'); +const nodeFromAnotherProgram = instructionLinkNode('myInstruction', 'myOtherProgram'); +``` diff --git a/v1/docs/linkNodes/PdaLinkNode.mdx b/v1/docs/linkNodes/PdaLinkNode.mdx index 8d79e02a..51cc9a81 100644 --- a/v1/docs/linkNodes/PdaLinkNode.mdx +++ b/v1/docs/linkNodes/PdaLinkNode.mdx @@ -16,3 +16,12 @@ A reference to a PDA defined elsewhere — possibly in a different program. | Attribute | Type | Description | | --------- | ------------------------------------------------------- | -------------------------------------------------------------------------------------------- | | `program` | [`ProgramLinkNode`](./ProgramLinkNode.mdx) _(optional)_ | The program the referenced PDA belongs to. When omitted, the surrounding program is assumed. | + +## Examples + +### Create a PDA link node from a PDA name + +```typescript +const node = pdaLinkNode('myPda'); +const nodeFromAnotherProgram = pdaLinkNode('myPda', 'myOtherProgram'); +``` diff --git a/v1/docs/linkNodes/ProgramLinkNode.mdx b/v1/docs/linkNodes/ProgramLinkNode.mdx index 215d2b1b..73fe08c3 100644 --- a/v1/docs/linkNodes/ProgramLinkNode.mdx +++ b/v1/docs/linkNodes/ProgramLinkNode.mdx @@ -10,3 +10,11 @@ A reference to a program by name. | --------- | ------------------- | ----------------------------------- | | `kind` | `"programLinkNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the referenced program. | + +## Examples + +### Create a program link node from a program name + +```typescript +const node = programLinkNode('myProgram'); +``` diff --git a/v1/docs/pdaSeedNodes/ConstantPdaSeedNode.mdx b/v1/docs/pdaSeedNodes/ConstantPdaSeedNode.mdx index 018f11e5..2a5d3695 100644 --- a/v1/docs/pdaSeedNodes/ConstantPdaSeedNode.mdx +++ b/v1/docs/pdaSeedNodes/ConstantPdaSeedNode.mdx @@ -16,3 +16,14 @@ A PDA seed with a constant value (e.g. a UTF-8 string or a fixed byte sequence). | --------- | ---------------------------------------------------- | --------------------------------------------------------------------------------------------- | | `type` | [`TypeNode`](../typeNodes/TypeNode.mdx) | The type of the seed value. | | `value` | [`ConstantPdaSeedValue`](./ConstantPdaSeedValue.mdx) | The constant value to use as the seed — either a literal value or the program ID placeholder. | + +## Examples + +### A PDA node with a UTF-8 constant seed + +```typescript +pdaNode({ + name: 'tickets', + seeds: [constantPdaSeedNodeFromString('utf8', 'tickets')], +}); +``` diff --git a/v1/docs/pdaSeedNodes/VariablePdaSeedNode.mdx b/v1/docs/pdaSeedNodes/VariablePdaSeedNode.mdx index 67c9abc1..0a843b65 100644 --- a/v1/docs/pdaSeedNodes/VariablePdaSeedNode.mdx +++ b/v1/docs/pdaSeedNodes/VariablePdaSeedNode.mdx @@ -17,3 +17,20 @@ A PDA seed whose value is provided at derivation time, identified by name. | Attribute | Type | Description | | --------- | --------------------------------------- | ------------------------------------ | | `type` | [`TypeNode`](../typeNodes/TypeNode.mdx) | The expected type of the seed value. | + +## Examples + +### Create a variable PDA seed node from a name and a type node + +```typescript +const node = variablePdaSeedNode('amount', numberTypeNode('u32')); +``` + +### A PDA node with a public key variable seed + +```typescript +pdaNode({ + name: 'ticket', + seeds: [variablePdaSeedNode('authority', publicKeyTypeNode())], +}); +``` diff --git a/v1/docs/typeNodes/AmountTypeNode.mdx b/v1/docs/typeNodes/AmountTypeNode.mdx index 71087efe..e0021e6f 100644 --- a/v1/docs/typeNodes/AmountTypeNode.mdx +++ b/v1/docs/typeNodes/AmountTypeNode.mdx @@ -17,3 +17,15 @@ Wraps a number type to provide additional context such as decimal places and a u | Attribute | Type | Description | | --------- | ----------------------------------------------------------------------------------- | --------------------------------- | | `number` | [`NestedTypeNode`](./NestedTypeNode.mdx)\<[`NumberTypeNode`](./NumberTypeNode.mdx)> | The number type the amount wraps. | + +## Examples + +### 2-decimals USD amount + +```typescript +amountTypeNode(numberTypeNode('u32'), 2, 'USD'); + +// 0.01 USD => 0x01000000 +// 10 USD => 0xE8030000 +// 400.60 USD => 0x7C9C0000 +``` diff --git a/v1/docs/typeNodes/ArrayTypeNode.mdx b/v1/docs/typeNodes/ArrayTypeNode.mdx index 23f3bb21..102cd1fc 100644 --- a/v1/docs/typeNodes/ArrayTypeNode.mdx +++ b/v1/docs/typeNodes/ArrayTypeNode.mdx @@ -16,3 +16,19 @@ A homogeneous list of items. The item type is defined by `item`; the length is d | --------- | ------------------------------------------ | --------------------------------------------------- | | `item` | [`TypeNode`](./TypeNode.mdx) | The type of each item in the array. | | `count` | [`CountNode`](../countNodes/CountNode.mdx) | The strategy used to determine the number of items. | + +## Examples + +### Create an array type node from a type node and a count node + +```typescript +const node = arrayTypeNode(publicKeyTypeNode(), prefixedCountNode(numberTypeNode('u32'))); +``` + +### u32 prefixed array of u8 numbers + +```typescript +arrayTypeNode(numberTypeNode('u8'), prefixedCountNode(numberTypeNode('u32'))); + +// [1, 2, 3] => 0x03000000010203 +``` diff --git a/v1/docs/typeNodes/BooleanTypeNode.mdx b/v1/docs/typeNodes/BooleanTypeNode.mdx index 719ca4db..53e5aed4 100644 --- a/v1/docs/typeNodes/BooleanTypeNode.mdx +++ b/v1/docs/typeNodes/BooleanTypeNode.mdx @@ -15,3 +15,23 @@ A boolean serialised as a numeric value. The wrapped number type determines the | Attribute | Type | Description | | --------- | ----------------------------------------------------------------------------------- | ----------------------------------------------- | | `size` | [`NestedTypeNode`](./NestedTypeNode.mdx)\<[`NumberTypeNode`](./NumberTypeNode.mdx)> | The numeric type used to serialise the boolean. | + +## Examples + +### u8 booleans + +```typescript +booleanTypeNode(); + +// true => 0x01 +// false => 0x00 +``` + +### u32 booleans + +```typescript +booleanTypeNode(numberTypeNode('u32')); + +// true => 0x01000000 +// false => 0x00000000 +``` diff --git a/v1/docs/typeNodes/BytesTypeNode.mdx b/v1/docs/typeNodes/BytesTypeNode.mdx index 4518f14e..9243ca2a 100644 --- a/v1/docs/typeNodes/BytesTypeNode.mdx +++ b/v1/docs/typeNodes/BytesTypeNode.mdx @@ -9,3 +9,11 @@ A raw sequence of bytes. Typically used inside a fixed-size, size-prefixed, or s | Attribute | Type | Description | | --------- | ----------------- | ----------------------- | | `kind` | `"bytesTypeNode"` | The node discriminator. | + +## Examples + +### Create a bytes type node + +```typescript +const node = bytesTypeNode(); +``` diff --git a/v1/docs/typeNodes/DateTimeTypeNode.mdx b/v1/docs/typeNodes/DateTimeTypeNode.mdx index ebcd174c..9bfd98c6 100644 --- a/v1/docs/typeNodes/DateTimeTypeNode.mdx +++ b/v1/docs/typeNodes/DateTimeTypeNode.mdx @@ -15,3 +15,19 @@ A timestamp encoded as a number, typically seconds since the Unix epoch. The wra | Attribute | Type | Description | | --------- | ----------------------------------------------------------------------------------- | ------------------------------------------------- | | `number` | [`NestedTypeNode`](./NestedTypeNode.mdx)\<[`NumberTypeNode`](./NumberTypeNode.mdx)> | The numeric type used to serialise the timestamp. | + +## Examples + +### Create a date time type node from a number type node + +```typescript +const node = dateTimeTypeNode(numberTypeNode('u64')); +``` + +### u64 unix datetime + +```typescript +dateTimeTypeNode(numberTypeNode('u64')); + +// 2024-06-27T14:57:56Z => 0xF47D7D6600000000 +``` diff --git a/v1/docs/typeNodes/EnumEmptyVariantTypeNode.mdx b/v1/docs/typeNodes/EnumEmptyVariantTypeNode.mdx index fd808922..0fb2cff1 100644 --- a/v1/docs/typeNodes/EnumEmptyVariantTypeNode.mdx +++ b/v1/docs/typeNodes/EnumEmptyVariantTypeNode.mdx @@ -17,3 +17,11 @@ A unit-style variant of an enum that carries no payload. | Attribute | Type | Description | | --------- | ----------------------------------------------------------------------------------- | --------------------------------------------------------- | | `display` | [`EnumVariantDisplayNode`](../displayNodes/EnumVariantDisplayNode.mdx) _(optional)_ | Display metadata describing how the variant is presented. | + +## Examples + +### Create an empty enum variant type node from a name + +```typescript +const node = enumEmptyVariantTypeNode('myVariantName'); +``` diff --git a/v1/docs/typeNodes/EnumStructVariantTypeNode.mdx b/v1/docs/typeNodes/EnumStructVariantTypeNode.mdx index 79bc8add..77e483df 100644 --- a/v1/docs/typeNodes/EnumStructVariantTypeNode.mdx +++ b/v1/docs/typeNodes/EnumStructVariantTypeNode.mdx @@ -18,3 +18,17 @@ A variant of an enum that carries a struct payload (named fields). | --------- | ----------------------------------------------------------------------------------- | --------------------------------------------------------- | | `struct` | [`NestedTypeNode`](./NestedTypeNode.mdx)\<[`StructTypeNode`](./StructTypeNode.mdx)> | The struct of named fields carried by the variant. | | `display` | [`EnumVariantDisplayNode`](../displayNodes/EnumVariantDisplayNode.mdx) _(optional)_ | Display metadata describing how the variant is presented. | + +## Examples + +### Create a struct enum variant type node from a name and a struct + +```typescript +const node = enumStructVariantTypeNode( + 'coordinates', + structTypeNode([ + structFieldTypeNode({ name: 'x', type: numberTypeNode('u32') }), + structFieldTypeNode({ name: 'y', type: numberTypeNode('u32') }), + ]), +); +``` diff --git a/v1/docs/typeNodes/EnumTupleVariantTypeNode.mdx b/v1/docs/typeNodes/EnumTupleVariantTypeNode.mdx index 3b0808e7..cfe98e8f 100644 --- a/v1/docs/typeNodes/EnumTupleVariantTypeNode.mdx +++ b/v1/docs/typeNodes/EnumTupleVariantTypeNode.mdx @@ -18,3 +18,11 @@ A variant of an enum that carries a tuple payload (positional fields). | --------- | ----------------------------------------------------------------------------------- | --------------------------------------------------------- | | `tuple` | [`NestedTypeNode`](./NestedTypeNode.mdx)\<[`TupleTypeNode`](./TupleTypeNode.mdx)> | The tuple of positional fields carried by the variant. | | `display` | [`EnumVariantDisplayNode`](../displayNodes/EnumVariantDisplayNode.mdx) _(optional)_ | Display metadata describing how the variant is presented. | + +## Examples + +### Create a tuple enum variant type node from a name and a tuple + +```typescript +const node = enumTupleVariantTypeNode('coordinates', tupleTypeNode([numberTypeNode('u32'), numberTypeNode('u32')])); +``` diff --git a/v1/docs/typeNodes/EnumTypeNode.mdx b/v1/docs/typeNodes/EnumTypeNode.mdx index ac3aeb36..110ce4c5 100644 --- a/v1/docs/typeNodes/EnumTypeNode.mdx +++ b/v1/docs/typeNodes/EnumTypeNode.mdx @@ -16,3 +16,25 @@ A tagged union: a numeric discriminator followed by one of several variant paylo | ---------- | ----------------------------------------------------------------------------------- | ----------------------------------------------------- | | `variants` | [`EnumVariantTypeNode`](./EnumVariantTypeNode.mdx)[] | The variants of the enum, in declaration order. | | `size` | [`NestedTypeNode`](./NestedTypeNode.mdx)\<[`NumberTypeNode`](./NumberTypeNode.mdx)> | The numeric type used to serialise the discriminator. | + +## Examples + +### Enum with u8 discriminator + +```typescript +enumTypeNode([ + enumEmptyVariantTypeNode('flip'), + enumTupleVariantTypeNode('rotate', tupleTypeNode([numberTypeNode('u32')])), + enumStructVariantTypeNode( + 'move', + structTypeNode([ + structFieldTypeNode({ name: 'x', type: numberTypeNode('u16') }), + structFieldTypeNode({ name: 'y', type: numberTypeNode('u16') }), + ]), + ), +]); + +// Flip => 0x00 +// Rotate (42) => 0x012A000000 +// Move { x: 1, y: 2 } => 0x0201000200 +``` diff --git a/v1/docs/typeNodes/FixedSizeTypeNode.mdx b/v1/docs/typeNodes/FixedSizeTypeNode.mdx index 63713e0a..2b745b3b 100644 --- a/v1/docs/typeNodes/FixedSizeTypeNode.mdx +++ b/v1/docs/typeNodes/FixedSizeTypeNode.mdx @@ -16,3 +16,28 @@ Wraps another type and asserts a fixed total byte size. Padding or truncation is | Attribute | Type | Description | | --------- | ---------------------------- | ---------------------------------------------------- | | `type` | [`TypeNode`](./TypeNode.mdx) | The wrapped type whose serialisation is constrained. | + +## Examples + +### Create a fixed size type node from a type node and a byte length + +```typescript +const node = fixedSizeTypeNode(stringTypeNode('utf8'), 32); +``` + +### Fixed UTF-8 strings + +```typescript +fixedSizeTypeNode(stringTypeNode('utf8'), 10); + +// Hello => 0x48656C6C6F0000000000 +``` + +### Fixed byte arrays + +```typescript +fixedSizeTypeNode(bytesTypeNode(), 4); + +// [1, 2] => 0x01020000 +// [1, 2, 3, 4, 5] => 0x01020304 +``` diff --git a/v1/docs/typeNodes/HiddenPrefixTypeNode.mdx b/v1/docs/typeNodes/HiddenPrefixTypeNode.mdx index 5c3b142c..fda78c66 100644 --- a/v1/docs/typeNodes/HiddenPrefixTypeNode.mdx +++ b/v1/docs/typeNodes/HiddenPrefixTypeNode.mdx @@ -16,3 +16,31 @@ Prefixes another type with a list of constant values that are written and read b | --------- | ------------------------------------------------------------ | ---------------------------------------------------------------------- | | `type` | [`TypeNode`](./TypeNode.mdx) | The wrapped type whose serialisation is preceded by the hidden prefix. | | `prefix` | [`ConstantValueNode`](../valueNodes/ConstantValueNode.mdx)[] | The constant values written before the wrapped type, in order. | + +## Examples + +### Create a hidden prefix type node from a type node and constant value nodes + +```typescript +const node = hiddenPrefixTypeNode(numberTypeNode('u32'), [ + constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffff')), +]); +``` + +### A number prefixed with 0xFFFF + +```typescript +hiddenPrefixTypeNode(numberTypeNode('u32'), [constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffff'))]); + +// 42 => 0xFFFF2A000000 +``` + +### A fixed UTF-8 string prefixed with "Hello" + +```typescript +hiddenPrefixTypeNode(fixedSizeTypeNode(stringTypeNode('utf8'), 10), [ + constantValueNode(stringTypeNode('utf8'), stringValueNode('Hello')), +]); + +// World => 0x48656C6C6F576F726C640000000000 +``` diff --git a/v1/docs/typeNodes/HiddenSuffixTypeNode.mdx b/v1/docs/typeNodes/HiddenSuffixTypeNode.mdx index b26ef72e..a552a543 100644 --- a/v1/docs/typeNodes/HiddenSuffixTypeNode.mdx +++ b/v1/docs/typeNodes/HiddenSuffixTypeNode.mdx @@ -16,3 +16,31 @@ Suffixes another type with a list of constant values that are written and read b | --------- | ------------------------------------------------------------ | ---------------------------------------------------------------------- | | `type` | [`TypeNode`](./TypeNode.mdx) | The wrapped type whose serialisation is followed by the hidden suffix. | | `suffix` | [`ConstantValueNode`](../valueNodes/ConstantValueNode.mdx)[] | The constant values written after the wrapped type, in order. | + +## Examples + +### Create a hidden suffix type node from a type node and constant value nodes + +```typescript +const node = hiddenSuffixTypeNode(numberTypeNode('u32'), [ + constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffff')), +]); +``` + +### A number suffixed with 0xFFFF + +```typescript +hiddenSuffixTypeNode(numberTypeNode('u32'), [constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffff'))]); + +// 42 => 0x2A000000FFFF +``` + +### A fixed UTF-8 string suffixed with "Hello" + +```typescript +hiddenSuffixTypeNode(fixedSizeTypeNode(stringTypeNode('utf8'), 10), [ + constantValueNode(stringTypeNode('utf8'), stringValueNode('Hello')), +]); + +// World => 0x576F726C64000000000048656c6c6F +``` diff --git a/v1/docs/typeNodes/MapTypeNode.mdx b/v1/docs/typeNodes/MapTypeNode.mdx index aee22350..714791db 100644 --- a/v1/docs/typeNodes/MapTypeNode.mdx +++ b/v1/docs/typeNodes/MapTypeNode.mdx @@ -17,3 +17,23 @@ A keyed map. The key and value types are described by their respective type node | `key` | [`TypeNode`](./TypeNode.mdx) | The type of each entry key. | | `value` | [`TypeNode`](./TypeNode.mdx) | The type of each entry value. | | `count` | [`CountNode`](../countNodes/CountNode.mdx) | The strategy used to determine the number of entries. | + +## Examples + +### Create a map type node from a key type, a value type, and a count node + +```typescript +const node = mapTypeNode(publicKeyTypeNode(), numberTypeNode('u32'), prefixedCountNode(numberTypeNode('u32'))); +``` + +### A histogram that counts letters + +```typescript +mapTypeNode( + fixedSizeTypeNode(stringTypeNode('utf8'), 1), // Key: Single UTF-8 character. + numberTypeNode('u16'), // Value: 16-bit unsigned integer. + prefixedCountNode(numberTypeNode('u8')), // Count: map length is prefixed with a u8. +); + +// { A: 42, B: 1, C: 16 } => 0x03412A00420100431000 +``` diff --git a/v1/docs/typeNodes/NumberTypeNode.mdx b/v1/docs/typeNodes/NumberTypeNode.mdx index 29d1a7d6..2f83879d 100644 --- a/v1/docs/typeNodes/NumberTypeNode.mdx +++ b/v1/docs/typeNodes/NumberTypeNode.mdx @@ -17,3 +17,35 @@ A numeric type with a fixed wire format and byte order. | `format` | [`NumberFormat`](../sharedNodes/NumberFormat.mdx) | The wire format used to serialise the number. | | `endian` | [`Endianness`](../sharedNodes/Endianness.mdx) | The byte order used to serialise the number. | | `display` | [`NumberDisplayNode`](../displayNodes/NumberDisplayNode.mdx) _(optional)_ | Display metadata describing how the number is presented. | + +## Examples + +### Encoding `u32` integers + +```typescript +numberTypeNode('u32'); + +// 5 => 0x05000000 +// 42 => 0x2A000000 +// 65535 => 0xFFFF0000 +``` + +### Encoding `f32` big-endian decimal numbers + +```typescript +numberTypeNode('f32', 'be'); + +// 1 => 0x3F800000 +// -42 => 0xC2280000 +// 3.1415 => 0x40490E56 +``` + +### Encoding `shortU16` integers + +```typescript +numberTypeNode('shortU16'); + +// 42 => 0x2A +// 128 => 0x8001 +// 16384 => 0x808001 +``` diff --git a/v1/docs/typeNodes/OptionTypeNode.mdx b/v1/docs/typeNodes/OptionTypeNode.mdx index c4d7b9ab..c38ba9b6 100644 --- a/v1/docs/typeNodes/OptionTypeNode.mdx +++ b/v1/docs/typeNodes/OptionTypeNode.mdx @@ -17,3 +17,23 @@ A value that may be present or absent (Some/None), with an explicit numeric pref | --------- | ----------------------------------------------------------------------------------- | -------------------------------------------- | | `item` | [`TypeNode`](./TypeNode.mdx) | The type carried by the option when present. | | `prefix` | [`NestedTypeNode`](./NestedTypeNode.mdx)\<[`NumberTypeNode`](./NumberTypeNode.mdx)> | The numeric type used as the presence flag. | + +## Examples + +### An optional UTF-8 with a u16 prefix + +```typescript +optionTypeNode(stringTypeNode('utf8'), { prefix: numberTypeNode('u16') }); + +// None => 0x0000 +// Some("Hello") => 0x010048656C6C6F +``` + +### A fixed optional u32 number + +```typescript +optionTypeNode(numberTypeNode('u32'), { fixed: true }); + +// None => 0x0000000000 +// Some(42) => 0x012A000000 +``` diff --git a/v1/docs/typeNodes/PostOffsetTypeNode.mdx b/v1/docs/typeNodes/PostOffsetTypeNode.mdx index fe5d57ad..b8f1323d 100644 --- a/v1/docs/typeNodes/PostOffsetTypeNode.mdx +++ b/v1/docs/typeNodes/PostOffsetTypeNode.mdx @@ -17,3 +17,34 @@ After serialising the wrapped type, advance the cursor by `offset` bytes interpr | ---------- | ------------------------------------------------------------- | --------------------------------------------------------------- | | `strategy` | [`PostOffsetStrategy`](../sharedNodes/PostOffsetStrategy.mdx) | How the `offset` value is interpreted. | | `type` | [`TypeNode`](./TypeNode.mdx) | The wrapped type whose serialisation is followed by the offset. | + +## Examples + +### A relative post-offset (the default strategy) + +```typescript +postOffsetTypeNode(numberTypeNode('u32'), 2); +``` + +### An absolute post-offset from the end of the buffer + +```typescript +postOffsetTypeNode(numberTypeNode('u32'), -2, 'absolute'); +``` + +### A right-padded u32 number + +```typescript +postOffsetTypeNode(numberTypeNode('u32'), 4, 'padded'); + +// 42 => 0x2A00000000000000 +``` + +### A u32 number overwritten by a u16 number + +```typescript +tupleTypeNode([postOffsetTypeNode(numberTypeNode('u32'), -2), numberTypeNode('u16')]); + +// [1, 2] => 0x01000200 +// [0xFFFFFFFF, 42] => 0xFFFF2A00 +``` diff --git a/v1/docs/typeNodes/PreOffsetTypeNode.mdx b/v1/docs/typeNodes/PreOffsetTypeNode.mdx index 4d262cda..98caa01b 100644 --- a/v1/docs/typeNodes/PreOffsetTypeNode.mdx +++ b/v1/docs/typeNodes/PreOffsetTypeNode.mdx @@ -17,3 +17,34 @@ Before serialising the wrapped type, advance the cursor by `offset` bytes interp | ---------- | ----------------------------------------------------------- | --------------------------------------------------------------- | | `strategy` | [`PreOffsetStrategy`](../sharedNodes/PreOffsetStrategy.mdx) | How the `offset` value is interpreted. | | `type` | [`TypeNode`](./TypeNode.mdx) | The wrapped type whose serialisation is preceded by the offset. | + +## Examples + +### A relative pre-offset (the default strategy) + +```typescript +preOffsetTypeNode(numberTypeNode('u32'), 2); +``` + +### An absolute pre-offset + +```typescript +preOffsetTypeNode(numberTypeNode('u32'), -2, 'absolute'); +``` + +### A left-padded u32 number + +```typescript +preOffsetTypeNode(numberTypeNode('u32'), 4, 'padded'); + +// 42 => 0x000000002A000000 +``` + +### A u32 number overwritten by a u16 number + +```typescript +tupleTypeNode([numberTypeNode('u32'), preOffsetTypeNode(numberTypeNode('u16'), -2)]); + +// [1, 2] => 0x01000200 +// [0xFFFFFFFF, 42] => 0xFFFF2A00 +``` diff --git a/v1/docs/typeNodes/PublicKeyTypeNode.mdx b/v1/docs/typeNodes/PublicKeyTypeNode.mdx index 27015a97..a1621211 100644 --- a/v1/docs/typeNodes/PublicKeyTypeNode.mdx +++ b/v1/docs/typeNodes/PublicKeyTypeNode.mdx @@ -9,3 +9,11 @@ A 32-byte Solana public key. | Attribute | Type | Description | | --------- | --------------------- | ----------------------- | | `kind` | `"publicKeyTypeNode"` | The node discriminator. | + +## Examples + +### Create a public key type node + +```typescript +const node = publicKeyTypeNode(); +``` diff --git a/v1/docs/typeNodes/RemainderOptionTypeNode.mdx b/v1/docs/typeNodes/RemainderOptionTypeNode.mdx index 1e8ec4a8..5c3af918 100644 --- a/v1/docs/typeNodes/RemainderOptionTypeNode.mdx +++ b/v1/docs/typeNodes/RemainderOptionTypeNode.mdx @@ -15,3 +15,14 @@ A value that may be present or absent. Presence is signalled by whether any byte | Attribute | Type | Description | | --------- | ---------------------------- | -------------------------------------------- | | `item` | [`TypeNode`](./TypeNode.mdx) | The type carried by the option when present. | + +## Examples + +### An optional UTF-8 string using remaining bytes + +```typescript +remainderOptionTypeNode(stringTypeNode('utf8')); + +// None => 0x +// Some("Hello") => 0x48656C6C6F +``` diff --git a/v1/docs/typeNodes/SentinelTypeNode.mdx b/v1/docs/typeNodes/SentinelTypeNode.mdx index 145d23fe..c17abe33 100644 --- a/v1/docs/typeNodes/SentinelTypeNode.mdx +++ b/v1/docs/typeNodes/SentinelTypeNode.mdx @@ -16,3 +16,13 @@ Wraps another type and delimits it with a constant sentinel value written immedi | ---------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------ | | `type` | [`TypeNode`](./TypeNode.mdx) | The wrapped type whose extent is delimited by the sentinel. | | `sentinel` | [`ConstantValueNode`](../valueNodes/ConstantValueNode.mdx) | The constant value written immediately after the wrapped type to mark its end. | + +## Examples + +### A UTF-8 string terminated by 0xFF + +```typescript +sentinelTypeNode(stringTypeNode('utf8'), constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ff'))); + +// Hello => 0x48656C6C6FFF +``` diff --git a/v1/docs/typeNodes/SetTypeNode.mdx b/v1/docs/typeNodes/SetTypeNode.mdx index 4d3e0522..4600dd2e 100644 --- a/v1/docs/typeNodes/SetTypeNode.mdx +++ b/v1/docs/typeNodes/SetTypeNode.mdx @@ -16,3 +16,13 @@ A unique-valued collection. The item type is defined by `item`; the size is dete | --------- | ------------------------------------------ | --------------------------------------------------- | | `item` | [`TypeNode`](./TypeNode.mdx) | The type of each item in the set. | | `count` | [`CountNode`](../countNodes/CountNode.mdx) | The strategy used to determine the number of items. | + +## Examples + +### u32 prefixed set of u8 numbers + +```typescript +setTypeNode(numberTypeNode('u8'), prefixedCountNode(numberTypeNode('u32'))); + +// Set (1, 2, 3) => 0x03000000010203 +``` diff --git a/v1/docs/typeNodes/SizePrefixTypeNode.mdx b/v1/docs/typeNodes/SizePrefixTypeNode.mdx index 6e253a41..cbaaaa3b 100644 --- a/v1/docs/typeNodes/SizePrefixTypeNode.mdx +++ b/v1/docs/typeNodes/SizePrefixTypeNode.mdx @@ -16,3 +16,14 @@ Wraps another type with a numeric prefix indicating the byte length of the wrapp | --------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------- | | `type` | [`TypeNode`](./TypeNode.mdx) | The wrapped type whose serialisation is preceded by its size. | | `prefix` | [`NestedTypeNode`](./NestedTypeNode.mdx)\<[`NumberTypeNode`](./NumberTypeNode.mdx)> | The numeric type used as the size prefix. | + +## Examples + +### A UTF-8 string prefixed with a u16 size + +```typescript +sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u16')); + +// "" => 0x0000 +// "Hello" => 0x050048656C6C6F +``` diff --git a/v1/docs/typeNodes/SolAmountTypeNode.mdx b/v1/docs/typeNodes/SolAmountTypeNode.mdx index 88300c35..4a543e63 100644 --- a/v1/docs/typeNodes/SolAmountTypeNode.mdx +++ b/v1/docs/typeNodes/SolAmountTypeNode.mdx @@ -15,3 +15,14 @@ A SOL amount expressed in lamports under the wrapped numeric type. | Attribute | Type | Description | | --------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------ | | `number` | [`NestedTypeNode`](./NestedTypeNode.mdx)\<[`NumberTypeNode`](./NumberTypeNode.mdx)> | The numeric type used to serialise the lamport amount. | + +## Examples + +### u64 Solana amounts + +```typescript +solAmountTypeNode(numberTypeNode('u64')); + +// 1.5 SOL => 0x002F685900000000 +// 300 SOL => 0x00B864D945000000 +``` diff --git a/v1/docs/typeNodes/StringTypeNode.mdx b/v1/docs/typeNodes/StringTypeNode.mdx index c955bb08..23486d24 100644 --- a/v1/docs/typeNodes/StringTypeNode.mdx +++ b/v1/docs/typeNodes/StringTypeNode.mdx @@ -16,3 +16,11 @@ A string value. The encoding describes how its bytes are written. The byte lengt | ---------- | ------------------------------------------------------------------------- | -------------------------------------------------------- | | `encoding` | [`BytesEncoding`](../sharedNodes/BytesEncoding.mdx) | The byte encoding used to serialise the string. | | `display` | [`StringDisplayNode`](../displayNodes/StringDisplayNode.mdx) _(optional)_ | Display metadata describing how the string is presented. | + +## Examples + +### Create a string type node from an encoding + +```typescript +const node = stringTypeNode('utf8'); +``` diff --git a/v1/docs/typeNodes/StructFieldTypeNode.mdx b/v1/docs/typeNodes/StructFieldTypeNode.mdx index c90a804a..6273a6fd 100644 --- a/v1/docs/typeNodes/StructFieldTypeNode.mdx +++ b/v1/docs/typeNodes/StructFieldTypeNode.mdx @@ -20,3 +20,18 @@ A named field within a struct type. | `type` | [`TypeNode`](./TypeNode.mdx) | The type of the field. | | `defaultValue` | [`ValueNode`](../valueNodes/ValueNode.mdx) _(optional)_ | A default value used when the field is omitted by callers. | | `display` | [`StructFieldDisplayNode`](../displayNodes/StructFieldDisplayNode.mdx) _(optional)_ | Display metadata describing how the field is presented. | + +## Examples + +### A struct field with a default value + +```typescript +structFieldTypeNode({ + name: 'age', + type: numberTypeNode('u8'), + defaultValue: numberValueNode(42), +}); + +// {} => 0x2A +// { age: 29 } => 0x1D +``` diff --git a/v1/docs/typeNodes/StructTypeNode.mdx b/v1/docs/typeNodes/StructTypeNode.mdx index 1c519d9a..c2775f30 100644 --- a/v1/docs/typeNodes/StructTypeNode.mdx +++ b/v1/docs/typeNodes/StructTypeNode.mdx @@ -15,3 +15,16 @@ A composite type made of an ordered list of named fields. Fields are encoded and | Attribute | Type | Description | | --------- | ---------------------------------------------------- | ----------------------------------------------- | | `fields` | [`StructFieldTypeNode`](./StructFieldTypeNode.mdx)[] | The fields of the struct, in declaration order. | + +## Examples + +### A struct storing a person's name and age + +```typescript +structTypeNode([ + structFieldTypeNode({ name: 'name', type: fixedSizeTypeNode(stringTypeNode('utf8'), 10) }), + structFieldTypeNode({ name: 'age', type: numberTypeNode('u8') }), +]); + +// { name: Alice, age: 42 } => 0x416C69636500000000002A +``` diff --git a/v1/docs/typeNodes/TupleTypeNode.mdx b/v1/docs/typeNodes/TupleTypeNode.mdx index 68db1e4e..5f2a24f9 100644 --- a/v1/docs/typeNodes/TupleTypeNode.mdx +++ b/v1/docs/typeNodes/TupleTypeNode.mdx @@ -15,3 +15,13 @@ A heterogeneous fixed-length sequence in which each positional slot has its own | Attribute | Type | Description | | --------- | ------------------------------ | ------------------------------------------- | | `items` | [`TypeNode`](./TypeNode.mdx)[] | The type of each positional slot, in order. | + +## Examples + +### A tuple storing a person's name and age + +```typescript +tupleTypeNode([fixedSizeTypeNode(stringTypeNode('utf8'), 10), numberTypeNode('u8')]); + +// (Alice, 42) => 0x416C69636500000000002A +``` diff --git a/v1/docs/typeNodes/ZeroableOptionTypeNode.mdx b/v1/docs/typeNodes/ZeroableOptionTypeNode.mdx index 4ab3005b..975a37b6 100644 --- a/v1/docs/typeNodes/ZeroableOptionTypeNode.mdx +++ b/v1/docs/typeNodes/ZeroableOptionTypeNode.mdx @@ -16,3 +16,23 @@ An optional value whose absence is signalled by a designated zero value rather t | ----------- | ----------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | `item` | [`TypeNode`](./TypeNode.mdx) | The type carried by the option when present. | | `zeroValue` | [`ConstantValueNode`](../valueNodes/ConstantValueNode.mdx) _(optional)_ | The constant value that signals absence. When omitted, the all-zero byte pattern of the item type is used. | + +## Examples + +### a u32 zeroable option + +```typescript +zeroableOptionTypeNode(numberTypeNode('u32')); + +// None => 0x00000000 +// Some(42) => 0x2A000000 +``` + +### a u32 zeroable option with a custom zero value + +```typescript +zeroableOptionTypeNode(numberTypeNode('u32'), constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffffffff'))); + +// None => 0xFFFFFFFF +// Some(42) => 0x2A000000 +``` diff --git a/v1/docs/valueNodes/ArrayValueNode.mdx b/v1/docs/valueNodes/ArrayValueNode.mdx index 36f21bf9..37259802 100644 --- a/v1/docs/valueNodes/ArrayValueNode.mdx +++ b/v1/docs/valueNodes/ArrayValueNode.mdx @@ -15,3 +15,11 @@ A concrete array value: a list of value nodes. | Attribute | Type | Description | | --------- | -------------------------------- | --------------------------------- | | `items` | [`ValueNode`](./ValueNode.mdx)[] | The items of the array, in order. | + +## Examples + +### Create an array value node from value nodes + +```typescript +const node = arrayValueNode([numberValueNode(1), numberValueNode(2), numberValueNode(3)]); +``` diff --git a/v1/docs/valueNodes/BooleanValueNode.mdx b/v1/docs/valueNodes/BooleanValueNode.mdx index 524a0521..299baf8b 100644 --- a/v1/docs/valueNodes/BooleanValueNode.mdx +++ b/v1/docs/valueNodes/BooleanValueNode.mdx @@ -10,3 +10,11 @@ A concrete boolean value. | --------- | -------------------- | ----------------------- | | `kind` | `"booleanValueNode"` | The node discriminator. | | `boolean` | `boolean` | The boolean value. | + +## Examples + +### Create a boolean value node from a boolean + +```typescript +const node = booleanValueNode(true); +``` diff --git a/v1/docs/valueNodes/BytesValueNode.mdx b/v1/docs/valueNodes/BytesValueNode.mdx index c52eeb8e..903e7792 100644 --- a/v1/docs/valueNodes/BytesValueNode.mdx +++ b/v1/docs/valueNodes/BytesValueNode.mdx @@ -16,3 +16,12 @@ A concrete bytes value, encoded as text in the chosen encoding. | Attribute | Type | Description | | ---------- | --------------------------------------------------- | ------------------------------------------------- | | `encoding` | [`BytesEncoding`](../sharedNodes/BytesEncoding.mdx) | The encoding used to represent the bytes as text. | + +## Examples + +### Create a bytes value node from an encoding and data + +```typescript +const node = bytesValueNode('base16', '010203'); +const utf8Node = bytesValueNode('utf8', 'Hello'); +``` diff --git a/v1/docs/valueNodes/ConstantValueNode.mdx b/v1/docs/valueNodes/ConstantValueNode.mdx index 4f54c11d..fcbd22b3 100644 --- a/v1/docs/valueNodes/ConstantValueNode.mdx +++ b/v1/docs/valueNodes/ConstantValueNode.mdx @@ -16,3 +16,11 @@ A typed constant: a type node paired with a concrete value node. | --------- | --------------------------------------- | ----------------------------------- | | `type` | [`TypeNode`](../typeNodes/TypeNode.mdx) | The type of the constant. | | `value` | [`ValueNode`](./ValueNode.mdx) | The concrete value of the constant. | + +## Examples + +### Create a constant value node from a type and a value node + +```typescript +const node = constantValueNode(numberTypeNode('u32'), numberValueNode(42)); +``` diff --git a/v1/docs/valueNodes/EnumValueNode.mdx b/v1/docs/valueNodes/EnumValueNode.mdx index b233d765..15fac5ed 100644 --- a/v1/docs/valueNodes/EnumValueNode.mdx +++ b/v1/docs/valueNodes/EnumValueNode.mdx @@ -17,3 +17,21 @@ A concrete value of a defined enum: a variant identifier plus an optional payloa | --------- | ------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | | `enum` | [`DefinedTypeLinkNode`](../linkNodes/DefinedTypeLinkNode.mdx) | A link to the defined enum type the value belongs to. | | `value` | [`EnumValuePayload`](./EnumValuePayload.mdx) _(optional)_ | The variant payload — a struct value for struct variants or a tuple value for tuple variants. | + +## Examples + +### Create an enum value node from an enum, a variant, and an optional value + +```typescript +const node = enumValueNode('myEnum', 'myVariant'); +const nodeWithExplicitEnum = enumValueNode(definedTypeLinkNode('myEnum'), 'myVariant'); + +const nodeWithData = enumValueNode( + 'myEnum', + 'myVariantWithData', + structValueNode([ + structFieldValueNode('name', stringValueNode('Alice')), + structFieldValueNode('age', numberValueNode(42)), + ]), +); +``` diff --git a/v1/docs/valueNodes/MapEntryValueNode.mdx b/v1/docs/valueNodes/MapEntryValueNode.mdx index b01b90a4..3adb6b5d 100644 --- a/v1/docs/valueNodes/MapEntryValueNode.mdx +++ b/v1/docs/valueNodes/MapEntryValueNode.mdx @@ -16,3 +16,11 @@ A single (key, value) pair inside a `mapValueNode`. | --------- | ------------------------------ | ---------------- | | `key` | [`ValueNode`](./ValueNode.mdx) | The entry key. | | `value` | [`ValueNode`](./ValueNode.mdx) | The entry value. | + +## Examples + +### Create a map entry value node from a key and a value + +```typescript +const node = mapEntryValueNode(stringValueNode('total'), numberValueNode(42)); +``` diff --git a/v1/docs/valueNodes/MapValueNode.mdx b/v1/docs/valueNodes/MapValueNode.mdx index d442e237..711b37cf 100644 --- a/v1/docs/valueNodes/MapValueNode.mdx +++ b/v1/docs/valueNodes/MapValueNode.mdx @@ -15,3 +15,15 @@ A concrete map value: a list of (key, value) entries. | Attribute | Type | Description | | --------- | ------------------------------------------------ | --------------------------------- | | `entries` | [`MapEntryValueNode`](./MapEntryValueNode.mdx)[] | The entries of the map, in order. | + +## Examples + +### Create a map value node from entries + +```typescript +const node = mapValueNode([ + mapEntryValueNode(stringValueNode('apples'), numberValueNode(12)), + mapEntryValueNode(stringValueNode('bananas'), numberValueNode(34)), + mapEntryValueNode(stringValueNode('carrots'), numberValueNode(56)), +]); +``` diff --git a/v1/docs/valueNodes/NoneValueNode.mdx b/v1/docs/valueNodes/NoneValueNode.mdx index 1624d436..72d87246 100644 --- a/v1/docs/valueNodes/NoneValueNode.mdx +++ b/v1/docs/valueNodes/NoneValueNode.mdx @@ -9,3 +9,11 @@ The "absent" value for an optional type. | Attribute | Type | Description | | --------- | ----------------- | ----------------------- | | `kind` | `"noneValueNode"` | The node discriminator. | + +## Examples + +### Create a none value node + +```typescript +const node = noneValueNode(); +``` diff --git a/v1/docs/valueNodes/NumberValueNode.mdx b/v1/docs/valueNodes/NumberValueNode.mdx index c6a3b929..a7810064 100644 --- a/v1/docs/valueNodes/NumberValueNode.mdx +++ b/v1/docs/valueNodes/NumberValueNode.mdx @@ -10,3 +10,11 @@ A concrete numeric value. Stored as a 64-bit float; consumers narrow to a specif | --------- | ------------------- | ----------------------- | | `kind` | `"numberValueNode"` | The node discriminator. | | `number` | `f64` | The numeric value. | + +## Examples + +### Create a number value node from a number + +```typescript +const node = numberValueNode(42); +``` diff --git a/v1/docs/valueNodes/PublicKeyValueNode.mdx b/v1/docs/valueNodes/PublicKeyValueNode.mdx index 3a660e46..41aed67c 100644 --- a/v1/docs/valueNodes/PublicKeyValueNode.mdx +++ b/v1/docs/valueNodes/PublicKeyValueNode.mdx @@ -11,3 +11,11 @@ A concrete public key, with an optional symbolic identifier for the address. | `kind` | `"publicKeyValueNode"` | The node discriminator. | | `publicKey` | `Address` | The base58-encoded public key. | | `identifier` | `CamelCaseString` _(optional)_ | A symbolic name for the address, useful in generated client code. | + +## Examples + +### Create a public key value node from a base58 public key + +```typescript +const node = publicKeyValueNode('7rA1KcBdW5hKmMasQdRVBFsD6T1nLtYuR6y59TJNgevR'); +``` diff --git a/v1/docs/valueNodes/SetValueNode.mdx b/v1/docs/valueNodes/SetValueNode.mdx index f4aed58a..17f8e681 100644 --- a/v1/docs/valueNodes/SetValueNode.mdx +++ b/v1/docs/valueNodes/SetValueNode.mdx @@ -15,3 +15,11 @@ A concrete set value: a list of unique value nodes. | Attribute | Type | Description | | --------- | -------------------------------- | --------------------- | | `items` | [`ValueNode`](./ValueNode.mdx)[] | The items of the set. | + +## Examples + +### Create a set value node from value nodes + +```typescript +const node = setValueNode([numberValueNode(1), numberValueNode(2), numberValueNode(3)]); +``` diff --git a/v1/docs/valueNodes/SomeValueNode.mdx b/v1/docs/valueNodes/SomeValueNode.mdx index f3c273d5..cbeebce8 100644 --- a/v1/docs/valueNodes/SomeValueNode.mdx +++ b/v1/docs/valueNodes/SomeValueNode.mdx @@ -15,3 +15,11 @@ The "present" value for an optional type, wrapping a concrete value node. | Attribute | Type | Description | | --------- | ------------------------------ | ------------------ | | `value` | [`ValueNode`](./ValueNode.mdx) | The wrapped value. | + +## Examples + +### Create a some value node from a value node + +```typescript +const node = someValueNode(numberValueNode(42)); +``` diff --git a/v1/docs/valueNodes/StringValueNode.mdx b/v1/docs/valueNodes/StringValueNode.mdx index 70f394a0..e152e5f5 100644 --- a/v1/docs/valueNodes/StringValueNode.mdx +++ b/v1/docs/valueNodes/StringValueNode.mdx @@ -10,3 +10,11 @@ A concrete string value. | --------- | ------------------- | ----------------------- | | `kind` | `"stringValueNode"` | The node discriminator. | | `string` | `string` | The string value. | + +## Examples + +### Create a string value node from a string + +```typescript +const node = stringValueNode('Hello'); +``` diff --git a/v1/docs/valueNodes/StructFieldValueNode.mdx b/v1/docs/valueNodes/StructFieldValueNode.mdx index 2e234e5f..e61d2c21 100644 --- a/v1/docs/valueNodes/StructFieldValueNode.mdx +++ b/v1/docs/valueNodes/StructFieldValueNode.mdx @@ -16,3 +16,11 @@ A named field of a `structValueNode`. | Attribute | Type | Description | | --------- | ------------------------------ | -------------------------------- | | `value` | [`ValueNode`](./ValueNode.mdx) | The concrete value of the field. | + +## Examples + +### Create a struct field value node from a name and a value + +```typescript +const node = structFieldValueNode('age', numberValueNode(42)); +``` diff --git a/v1/docs/valueNodes/StructValueNode.mdx b/v1/docs/valueNodes/StructValueNode.mdx index ffe5fa1b..aad3a548 100644 --- a/v1/docs/valueNodes/StructValueNode.mdx +++ b/v1/docs/valueNodes/StructValueNode.mdx @@ -15,3 +15,14 @@ A concrete struct value: a list of named field values. | Attribute | Type | Description | | --------- | ------------------------------------------------------ | ------------------------------------- | | `fields` | [`StructFieldValueNode`](./StructFieldValueNode.mdx)[] | The named fields of the struct value. | + +## Examples + +### Create a struct value node from field value nodes + +```typescript +const node = structValueNode([ + structFieldValueNode('name', stringValueNode('Alice')), + structFieldValueNode('age', numberValueNode(42)), +]); +``` diff --git a/v1/docs/valueNodes/TupleValueNode.mdx b/v1/docs/valueNodes/TupleValueNode.mdx index 368c8113..7c903359 100644 --- a/v1/docs/valueNodes/TupleValueNode.mdx +++ b/v1/docs/valueNodes/TupleValueNode.mdx @@ -15,3 +15,11 @@ A concrete tuple value: a fixed-length sequence of positional value nodes. | Attribute | Type | Description | | --------- | -------------------------------- | -------------------------------------------- | | `items` | [`ValueNode`](./ValueNode.mdx)[] | The positional items of the tuple, in order. | + +## Examples + +### Create a tuple value node from value nodes + +```typescript +const node = tupleValueNode([stringValueNode('Alice'), numberValueNode(42)]); +``` diff --git a/v1/spec.json b/v1/spec.json index f5adf676..1a14291b 100644 --- a/v1/spec.json +++ b/v1/spec.json @@ -47,7 +47,23 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "2-decimals USD amount", + "code": [ + { + "language": "typescript", + "content": [ + "amountTypeNode(numberTypeNode('u32'), 2, 'USD');", + "", + "// 0.01 USD => 0x01000000", + "// 10 USD => 0xE8030000", + "// 400.60 USD => 0x7C9C0000" + ] + } + ] + } + ] }, { "kind": "arrayTypeNode", @@ -76,7 +92,32 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create an array type node from a type node and a count node", + "code": [ + { + "language": "typescript", + "content": [ + "const node = arrayTypeNode(publicKeyTypeNode(), prefixedCountNode(numberTypeNode('u32')));" + ] + } + ] + }, + { + "title": "u32 prefixed array of u8 numbers", + "code": [ + { + "language": "typescript", + "content": [ + "arrayTypeNode(numberTypeNode('u8'), prefixedCountNode(numberTypeNode('u32')));", + "", + "// [1, 2, 3] => 0x03000000010203" + ] + } + ] + } + ] }, { "kind": "booleanTypeNode", @@ -96,7 +137,36 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "u8 booleans", + "code": [ + { + "language": "typescript", + "content": [ + "booleanTypeNode();", + "", + "// true => 0x01", + "// false => 0x00" + ] + } + ] + }, + { + "title": "u32 booleans", + "code": [ + { + "language": "typescript", + "content": [ + "booleanTypeNode(numberTypeNode('u32'));", + "", + "// true => 0x01000000", + "// false => 0x00000000" + ] + } + ] + } + ] }, { "kind": "bytesTypeNode", @@ -104,7 +174,19 @@ "A raw sequence of bytes. Typically used inside a fixed-size, size-prefixed, or sentinel-terminated wrapper." ], "attributes": [], - "examples": [] + "examples": [ + { + "title": "Create a bytes type node", + "code": [ + { + "language": "typescript", + "content": [ + "const node = bytesTypeNode();" + ] + } + ] + } + ] }, { "kind": "dateTimeTypeNode", @@ -124,7 +206,32 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a date time type node from a number type node", + "code": [ + { + "language": "typescript", + "content": [ + "const node = dateTimeTypeNode(numberTypeNode('u64'));" + ] + } + ] + }, + { + "title": "u64 unix datetime", + "code": [ + { + "language": "typescript", + "content": [ + "dateTimeTypeNode(numberTypeNode('u64'));", + "", + "// 2024-06-27T14:57:56Z => 0xF47D7D6600000000" + ] + } + ] + } + ] }, { "kind": "enumEmptyVariantTypeNode", @@ -165,7 +272,19 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create an empty enum variant type node from a name", + "code": [ + { + "language": "typescript", + "content": [ + "const node = enumEmptyVariantTypeNode('myVariantName');" + ] + } + ] + } + ] }, { "kind": "enumStructVariantTypeNode", @@ -217,7 +336,25 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a struct enum variant type node from a name and a struct", + "code": [ + { + "language": "typescript", + "content": [ + "const node = enumStructVariantTypeNode(", + " 'coordinates',", + " structTypeNode([", + " structFieldTypeNode({ name: 'x', type: numberTypeNode('u32') }),", + " structFieldTypeNode({ name: 'y', type: numberTypeNode('u32') }),", + " ]),", + ");" + ] + } + ] + } + ] }, { "kind": "enumTupleVariantTypeNode", @@ -269,7 +406,19 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a tuple enum variant type node from a name and a tuple", + "code": [ + { + "language": "typescript", + "content": [ + "const node = enumTupleVariantTypeNode('coordinates', tupleTypeNode([numberTypeNode('u32'), numberTypeNode('u32')]));" + ] + } + ] + } + ] }, { "kind": "enumTypeNode", @@ -302,7 +451,33 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Enum with u8 discriminator", + "code": [ + { + "language": "typescript", + "content": [ + "enumTypeNode([", + " enumEmptyVariantTypeNode('flip'),", + " enumTupleVariantTypeNode('rotate', tupleTypeNode([numberTypeNode('u32')])),", + " enumStructVariantTypeNode(", + " 'move',", + " structTypeNode([", + " structFieldTypeNode({ name: 'x', type: numberTypeNode('u16') }),", + " structFieldTypeNode({ name: 'y', type: numberTypeNode('u16') }),", + " ]),", + " ),", + "]);", + "", + "// Flip => 0x00", + "// Rotate (42) => 0x012A000000", + "// Move { x: 1, y: 2 } => 0x0201000200" + ] + } + ] + } + ] }, { "kind": "fixedSizeTypeNode", @@ -331,7 +506,46 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a fixed size type node from a type node and a byte length", + "code": [ + { + "language": "typescript", + "content": [ + "const node = fixedSizeTypeNode(stringTypeNode('utf8'), 32);" + ] + } + ] + }, + { + "title": "Fixed UTF-8 strings", + "code": [ + { + "language": "typescript", + "content": [ + "fixedSizeTypeNode(stringTypeNode('utf8'), 10);", + "", + "// Hello => 0x48656C6C6F0000000000" + ] + } + ] + }, + { + "title": "Fixed byte arrays", + "code": [ + { + "language": "typescript", + "content": [ + "fixedSizeTypeNode(bytesTypeNode(), 4);", + "", + "// [1, 2] => 0x01020000", + "// [1, 2, 3, 4, 5] => 0x01020304" + ] + } + ] + } + ] }, { "kind": "hiddenPrefixTypeNode", @@ -363,7 +577,49 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a hidden prefix type node from a type node and constant value nodes", + "code": [ + { + "language": "typescript", + "content": [ + "const node = hiddenPrefixTypeNode(numberTypeNode('u32'), [", + " constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffff')),", + "]);" + ] + } + ] + }, + { + "title": "A number prefixed with 0xFFFF", + "code": [ + { + "language": "typescript", + "content": [ + "hiddenPrefixTypeNode(numberTypeNode('u32'), [constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffff'))]);", + "", + "// 42 => 0xFFFF2A000000" + ] + } + ] + }, + { + "title": "A fixed UTF-8 string prefixed with \"Hello\"", + "code": [ + { + "language": "typescript", + "content": [ + "hiddenPrefixTypeNode(fixedSizeTypeNode(stringTypeNode('utf8'), 10), [", + " constantValueNode(stringTypeNode('utf8'), stringValueNode('Hello')),", + "]);", + "", + "// World => 0x48656C6C6F576F726C640000000000" + ] + } + ] + } + ] }, { "kind": "hiddenSuffixTypeNode", @@ -395,7 +651,49 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a hidden suffix type node from a type node and constant value nodes", + "code": [ + { + "language": "typescript", + "content": [ + "const node = hiddenSuffixTypeNode(numberTypeNode('u32'), [", + " constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffff')),", + "]);" + ] + } + ] + }, + { + "title": "A number suffixed with 0xFFFF", + "code": [ + { + "language": "typescript", + "content": [ + "hiddenSuffixTypeNode(numberTypeNode('u32'), [constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffff'))]);", + "", + "// 42 => 0x2A000000FFFF" + ] + } + ] + }, + { + "title": "A fixed UTF-8 string suffixed with \"Hello\"", + "code": [ + { + "language": "typescript", + "content": [ + "hiddenSuffixTypeNode(fixedSizeTypeNode(stringTypeNode('utf8'), 10), [", + " constantValueNode(stringTypeNode('utf8'), stringValueNode('Hello')),", + "]);", + "", + "// World => 0x576F726C64000000000048656c6c6F" + ] + } + ] + } + ] }, { "kind": "mapTypeNode", @@ -435,7 +733,36 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a map type node from a key type, a value type, and a count node", + "code": [ + { + "language": "typescript", + "content": [ + "const node = mapTypeNode(publicKeyTypeNode(), numberTypeNode('u32'), prefixedCountNode(numberTypeNode('u32')));" + ] + } + ] + }, + { + "title": "A histogram that counts letters", + "code": [ + { + "language": "typescript", + "content": [ + "mapTypeNode(", + " fixedSizeTypeNode(stringTypeNode('utf8'), 1), // Key: Single UTF-8 character.", + " numberTypeNode('u16'), // Value: 16-bit unsigned integer.", + " prefixedCountNode(numberTypeNode('u8')), // Count: map length is prefixed with a u8.", + ");", + "", + "// { A: 42, B: 1, C: 16 } => 0x03412A00420100431000" + ] + } + ] + } + ] }, { "kind": "numberTypeNode", @@ -475,7 +802,53 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Encoding `u32` integers", + "code": [ + { + "language": "typescript", + "content": [ + "numberTypeNode('u32');", + "", + "// 5 => 0x05000000", + "// 42 => 0x2A000000", + "// 65535 => 0xFFFF0000" + ] + } + ] + }, + { + "title": "Encoding `f32` big-endian decimal numbers", + "code": [ + { + "language": "typescript", + "content": [ + "numberTypeNode('f32', 'be');", + "", + "// 1 => 0x3F800000", + "// -42 => 0xC2280000", + "// 3.1415 => 0x40490E56" + ] + } + ] + }, + { + "title": "Encoding `shortU16` integers", + "code": [ + { + "language": "typescript", + "content": [ + "numberTypeNode('shortU16');", + "", + "// 42 => 0x2A", + "// 128 => 0x8001", + "// 16384 => 0x808001" + ] + } + ] + } + ] }, { "kind": "optionTypeNode", @@ -515,7 +888,36 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "An optional UTF-8 with a u16 prefix", + "code": [ + { + "language": "typescript", + "content": [ + "optionTypeNode(stringTypeNode('utf8'), { prefix: numberTypeNode('u16') });", + "", + "// None => 0x0000", + "// Some(\"Hello\") => 0x010048656C6C6F" + ] + } + ] + }, + { + "title": "A fixed optional u32 number", + "code": [ + { + "language": "typescript", + "content": [ + "optionTypeNode(numberTypeNode('u32'), { fixed: true });", + "", + "// None => 0x0000000000", + "// Some(42) => 0x012A000000" + ] + } + ] + } + ] }, { "kind": "postOffsetTypeNode", @@ -554,7 +956,57 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "A relative post-offset (the default strategy)", + "code": [ + { + "language": "typescript", + "content": [ + "postOffsetTypeNode(numberTypeNode('u32'), 2);" + ] + } + ] + }, + { + "title": "An absolute post-offset from the end of the buffer", + "code": [ + { + "language": "typescript", + "content": [ + "postOffsetTypeNode(numberTypeNode('u32'), -2, 'absolute');" + ] + } + ] + }, + { + "title": "A right-padded u32 number", + "code": [ + { + "language": "typescript", + "content": [ + "postOffsetTypeNode(numberTypeNode('u32'), 4, 'padded');", + "", + "// 42 => 0x2A00000000000000" + ] + } + ] + }, + { + "title": "A u32 number overwritten by a u16 number", + "code": [ + { + "language": "typescript", + "content": [ + "tupleTypeNode([postOffsetTypeNode(numberTypeNode('u32'), -2), numberTypeNode('u16')]);", + "", + "// [1, 2] => 0x01000200", + "// [0xFFFFFFFF, 42] => 0xFFFF2A00" + ] + } + ] + } + ] }, { "kind": "preOffsetTypeNode", @@ -593,7 +1045,57 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "A relative pre-offset (the default strategy)", + "code": [ + { + "language": "typescript", + "content": [ + "preOffsetTypeNode(numberTypeNode('u32'), 2);" + ] + } + ] + }, + { + "title": "An absolute pre-offset", + "code": [ + { + "language": "typescript", + "content": [ + "preOffsetTypeNode(numberTypeNode('u32'), -2, 'absolute');" + ] + } + ] + }, + { + "title": "A left-padded u32 number", + "code": [ + { + "language": "typescript", + "content": [ + "preOffsetTypeNode(numberTypeNode('u32'), 4, 'padded');", + "", + "// 42 => 0x000000002A000000" + ] + } + ] + }, + { + "title": "A u32 number overwritten by a u16 number", + "code": [ + { + "language": "typescript", + "content": [ + "tupleTypeNode([numberTypeNode('u32'), preOffsetTypeNode(numberTypeNode('u16'), -2)]);", + "", + "// [1, 2] => 0x01000200", + "// [0xFFFFFFFF, 42] => 0xFFFF2A00" + ] + } + ] + } + ] }, { "kind": "publicKeyTypeNode", @@ -601,7 +1103,19 @@ "A 32-byte Solana public key." ], "attributes": [], - "examples": [] + "examples": [ + { + "title": "Create a public key type node", + "code": [ + { + "language": "typescript", + "content": [ + "const node = publicKeyTypeNode();" + ] + } + ] + } + ] }, { "kind": "remainderOptionTypeNode", @@ -620,7 +1134,22 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "An optional UTF-8 string using remaining bytes", + "code": [ + { + "language": "typescript", + "content": [ + "remainderOptionTypeNode(stringTypeNode('utf8'));", + "", + "// None => 0x", + "// Some(\"Hello\") => 0x48656C6C6F" + ] + } + ] + } + ] }, { "kind": "sentinelTypeNode", @@ -649,7 +1178,21 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "A UTF-8 string terminated by 0xFF", + "code": [ + { + "language": "typescript", + "content": [ + "sentinelTypeNode(stringTypeNode('utf8'), constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ff')));", + "", + "// Hello => 0x48656C6C6FFF" + ] + } + ] + } + ] }, { "kind": "setTypeNode", @@ -678,7 +1221,21 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "u32 prefixed set of u8 numbers", + "code": [ + { + "language": "typescript", + "content": [ + "setTypeNode(numberTypeNode('u8'), prefixedCountNode(numberTypeNode('u32')));", + "", + "// Set (1, 2, 3) => 0x03000000010203" + ] + } + ] + } + ] }, { "kind": "sizePrefixTypeNode", @@ -708,7 +1265,22 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "A UTF-8 string prefixed with a u16 size", + "code": [ + { + "language": "typescript", + "content": [ + "sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u16'));", + "", + "// \"\" => 0x0000", + "// \"Hello\" => 0x050048656C6C6F" + ] + } + ] + } + ] }, { "kind": "solAmountTypeNode", @@ -728,7 +1300,22 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "u64 Solana amounts", + "code": [ + { + "language": "typescript", + "content": [ + "solAmountTypeNode(numberTypeNode('u64'));", + "", + "// 1.5 SOL => 0x002F685900000000", + "// 300 SOL => 0x00B864D945000000" + ] + } + ] + } + ] }, { "kind": "stringTypeNode", @@ -760,7 +1347,19 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a string type node from an encoding", + "code": [ + { + "language": "typescript", + "content": [ + "const node = stringTypeNode('utf8');" + ] + } + ] + } + ] }, { "kind": "structFieldTypeNode", @@ -832,7 +1431,26 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "A struct field with a default value", + "code": [ + { + "language": "typescript", + "content": [ + "structFieldTypeNode({", + " name: 'age',", + " type: numberTypeNode('u8'),", + " defaultValue: numberValueNode(42),", + "});", + "", + "// {} => 0x2A", + "// { age: 29 } => 0x1D" + ] + } + ] + } + ] }, { "kind": "structTypeNode", @@ -854,7 +1472,24 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "A struct storing a person's name and age", + "code": [ + { + "language": "typescript", + "content": [ + "structTypeNode([", + " structFieldTypeNode({ name: 'name', type: fixedSizeTypeNode(stringTypeNode('utf8'), 10) }),", + " structFieldTypeNode({ name: 'age', type: numberTypeNode('u8') }),", + "]);", + "", + "// { name: Alice, age: 42 } => 0x416C69636500000000002A" + ] + } + ] + } + ] }, { "kind": "tupleTypeNode", @@ -876,7 +1511,21 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "A tuple storing a person's name and age", + "code": [ + { + "language": "typescript", + "content": [ + "tupleTypeNode([fixedSizeTypeNode(stringTypeNode('utf8'), 10), numberTypeNode('u8')]);", + "", + "// (Alice, 42) => 0x416C69636500000000002A" + ] + } + ] + } + ] }, { "kind": "zeroableOptionTypeNode", @@ -906,7 +1555,36 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "a u32 zeroable option", + "code": [ + { + "language": "typescript", + "content": [ + "zeroableOptionTypeNode(numberTypeNode('u32'));", + "", + "// None => 0x00000000", + "// Some(42) => 0x2A000000" + ] + } + ] + }, + { + "title": "a u32 zeroable option with a custom zero value", + "code": [ + { + "language": "typescript", + "content": [ + "zeroableOptionTypeNode(numberTypeNode('u32'), constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffffffff')));", + "", + "// None => 0xFFFFFFFF", + "// Some(42) => 0x2A000000" + ] + } + ] + } + ] } ], "unions": [ @@ -1121,7 +1799,19 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create an array value node from value nodes", + "code": [ + { + "language": "typescript", + "content": [ + "const node = arrayValueNode([numberValueNode(1), numberValueNode(2), numberValueNode(3)]);" + ] + } + ] + } + ] }, { "kind": "booleanValueNode", @@ -1139,7 +1829,19 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a boolean value node from a boolean", + "code": [ + { + "language": "typescript", + "content": [ + "const node = booleanValueNode(true);" + ] + } + ] + } + ] }, { "kind": "bytesValueNode", @@ -1167,7 +1869,20 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a bytes value node from an encoding and data", + "code": [ + { + "language": "typescript", + "content": [ + "const node = bytesValueNode('base16', '010203');", + "const utf8Node = bytesValueNode('utf8', 'Hello');" + ] + } + ] + } + ] }, { "kind": "constantValueNode", @@ -1196,7 +1911,19 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a constant value node from a type and a value node", + "code": [ + { + "language": "typescript", + "content": [ + "const node = constantValueNode(numberTypeNode('u32'), numberValueNode(42));" + ] + } + ] + } + ] }, { "kind": "enumValueNode", @@ -1237,7 +1964,29 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create an enum value node from an enum, a variant, and an optional value", + "code": [ + { + "language": "typescript", + "content": [ + "const node = enumValueNode('myEnum', 'myVariant');", + "const nodeWithExplicitEnum = enumValueNode(definedTypeLinkNode('myEnum'), 'myVariant');", + "", + "const nodeWithData = enumValueNode(", + " 'myEnum',", + " 'myVariantWithData',", + " structValueNode([", + " structFieldValueNode('name', stringValueNode('Alice')),", + " structFieldValueNode('age', numberValueNode(42)),", + " ]),", + ");" + ] + } + ] + } + ] }, { "kind": "injectedValueNode", @@ -1299,7 +2048,19 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a map entry value node from a key and a value", + "code": [ + { + "language": "typescript", + "content": [ + "const node = mapEntryValueNode(stringValueNode('total'), numberValueNode(42));" + ] + } + ] + } + ] }, { "kind": "mapValueNode", @@ -1321,7 +2082,23 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a map value node from entries", + "code": [ + { + "language": "typescript", + "content": [ + "const node = mapValueNode([", + " mapEntryValueNode(stringValueNode('apples'), numberValueNode(12)),", + " mapEntryValueNode(stringValueNode('bananas'), numberValueNode(34)),", + " mapEntryValueNode(stringValueNode('carrots'), numberValueNode(56)),", + "]);" + ] + } + ] + } + ] }, { "kind": "noneValueNode", @@ -1329,7 +2106,19 @@ "The \"absent\" value for an optional type." ], "attributes": [], - "examples": [] + "examples": [ + { + "title": "Create a none value node", + "code": [ + { + "language": "typescript", + "content": [ + "const node = noneValueNode();" + ] + } + ] + } + ] }, { "kind": "numberValueNode", @@ -1348,8 +2137,20 @@ "The numeric value." ] } - ], - "examples": [] + ], + "examples": [ + { + "title": "Create a number value node from a number", + "code": [ + { + "language": "typescript", + "content": [ + "const node = numberValueNode(42);" + ] + } + ] + } + ] }, { "kind": "publicKeyValueNode", @@ -1378,7 +2179,19 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a public key value node from a base58 public key", + "code": [ + { + "language": "typescript", + "content": [ + "const node = publicKeyValueNode('7rA1KcBdW5hKmMasQdRVBFsD6T1nLtYuR6y59TJNgevR');" + ] + } + ] + } + ] }, { "kind": "setValueNode", @@ -1400,7 +2213,19 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a set value node from value nodes", + "code": [ + { + "language": "typescript", + "content": [ + "const node = setValueNode([numberValueNode(1), numberValueNode(2), numberValueNode(3)]);" + ] + } + ] + } + ] }, { "kind": "someValueNode", @@ -1419,7 +2244,19 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a some value node from a value node", + "code": [ + { + "language": "typescript", + "content": [ + "const node = someValueNode(numberValueNode(42));" + ] + } + ] + } + ] }, { "kind": "stringValueNode", @@ -1437,7 +2274,19 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a string value node from a string", + "code": [ + { + "language": "typescript", + "content": [ + "const node = stringValueNode('Hello');" + ] + } + ] + } + ] }, { "kind": "structFieldValueNode", @@ -1466,7 +2315,19 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a struct field value node from a name and a value", + "code": [ + { + "language": "typescript", + "content": [ + "const node = structFieldValueNode('age', numberValueNode(42));" + ] + } + ] + } + ] }, { "kind": "structValueNode", @@ -1488,7 +2349,22 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a struct value node from field value nodes", + "code": [ + { + "language": "typescript", + "content": [ + "const node = structValueNode([", + " structFieldValueNode('name', stringValueNode('Alice')),", + " structFieldValueNode('age', numberValueNode(42)),", + "]);" + ] + } + ] + } + ] }, { "kind": "tupleValueNode", @@ -1510,7 +2386,19 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a tuple value node from value nodes", + "code": [ + { + "language": "typescript", + "content": [ + "const node = tupleValueNode([stringValueNode('Alice'), numberValueNode(42)]);" + ] + } + ] + } + ] } ], "unions": [ @@ -1700,7 +2588,20 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create an account link node from an account name", + "code": [ + { + "language": "typescript", + "content": [ + "const node = accountLinkNode('myAccount');", + "const nodeFromAnotherProgram = accountLinkNode('myAccount', 'myOtherProgram');" + ] + } + ] + } + ] }, { "kind": "definedTypeLinkNode", @@ -1730,7 +2631,20 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a defined type link node from a type name", + "code": [ + { + "language": "typescript", + "content": [ + "const node = definedTypeLinkNode('myDefinedType');", + "const nodeFromAnotherProgram = definedTypeLinkNode('myDefinedType', 'myOtherProgram');" + ] + } + ] + } + ] }, { "kind": "instructionAccountLinkNode", @@ -1760,7 +2674,29 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create an instruction account link node from an account name", + "code": [ + { + "language": "typescript", + "content": [ + "// Links to an account in the current instruction.", + "const node = instructionAccountLinkNode('myAccount');", + "", + "// Links to an account in another instruction but within the same program.", + "const nodeFromAnotherInstruction = instructionAccountLinkNode('myAccount', 'myOtherInstruction');", + "", + "// Links to an account in another instruction from another program.", + "const nodeFromAnotherProgram = instructionAccountLinkNode(", + " 'myAccount',", + " instructionLinkNode('myOtherInstruction', 'myOtherProgram'),", + ");" + ] + } + ] + } + ] }, { "kind": "instructionArgumentLinkNode", @@ -1790,7 +2726,29 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create an instruction argument link node from an argument name", + "code": [ + { + "language": "typescript", + "content": [ + "// Links to an argument in the current instruction.", + "const node = instructionArgumentLinkNode('myArgument');", + "", + "// Links to an argument in another instruction but within the same program.", + "const nodeFromAnotherInstruction = instructionArgumentLinkNode('myArgument', 'myOtherInstruction');", + "", + "// Links to an argument in another instruction from another program.", + "const nodeFromAnotherProgram = instructionArgumentLinkNode(", + " 'myArgument',", + " instructionLinkNode('myOtherInstruction', 'myOtherProgram'),", + ");" + ] + } + ] + } + ] }, { "kind": "instructionLinkNode", @@ -1820,7 +2778,20 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create an instruction link node from an instruction name", + "code": [ + { + "language": "typescript", + "content": [ + "const node = instructionLinkNode('myInstruction');", + "const nodeFromAnotherProgram = instructionLinkNode('myInstruction', 'myOtherProgram');" + ] + } + ] + } + ] }, { "kind": "pdaLinkNode", @@ -1850,7 +2821,20 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a PDA link node from a PDA name", + "code": [ + { + "language": "typescript", + "content": [ + "const node = pdaLinkNode('myPda');", + "const nodeFromAnotherProgram = pdaLinkNode('myPda', 'myOtherProgram');" + ] + } + ] + } + ] }, { "kind": "programLinkNode", @@ -1869,7 +2853,19 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a program link node from a program name", + "code": [ + { + "language": "typescript", + "content": [ + "const node = programLinkNode('myProgram');" + ] + } + ] + } + ] } ], "unions": [ @@ -1958,7 +2954,22 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "A PDA node with a UTF-8 constant seed", + "code": [ + { + "language": "typescript", + "content": [ + "pdaNode({", + " name: 'tickets',", + " seeds: [constantPdaSeedNodeFromString('utf8', 'tickets')],", + "});" + ] + } + ] + } + ] }, { "kind": "variablePdaSeedNode", @@ -1997,7 +3008,33 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a variable PDA seed node from a name and a type node", + "code": [ + { + "language": "typescript", + "content": [ + "const node = variablePdaSeedNode('amount', numberTypeNode('u32'));" + ] + } + ] + }, + { + "title": "A PDA node with a public key variable seed", + "code": [ + { + "language": "typescript", + "content": [ + "pdaNode({", + " name: 'ticket',", + " seeds: [variablePdaSeedNode('authority', publicKeyTypeNode())],", + "});" + ] + } + ] + } + ] } ], "unions": [ @@ -2072,7 +3109,30 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a fixed count node from a number", + "code": [ + { + "language": "typescript", + "content": [ + "const node = fixedCountNode(42);" + ] + } + ] + }, + { + "title": "An array of three public keys", + "code": [ + { + "language": "typescript", + "content": [ + "arrayTypeNode(publicKeyTypeNode(), fixedCountNode(3));" + ] + } + ] + } + ] }, { "kind": "prefixedCountNode", @@ -2092,7 +3152,30 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a prefixed count node from a number node", + "code": [ + { + "language": "typescript", + "content": [ + "const node = prefixedCountNode(numberTypeNode('u32'));" + ] + } + ] + }, + { + "title": "A variable array of public keys prefixed with a u32", + "code": [ + { + "language": "typescript", + "content": [ + "arrayTypeNode(publicKeyTypeNode(), prefixedCountNode(numberTypeNode('u32')));" + ] + } + ] + } + ] }, { "kind": "remainderCountNode", @@ -2100,7 +3183,30 @@ "A count strategy where items are read until the buffer is exhausted." ], "attributes": [], - "examples": [] + "examples": [ + { + "title": "Create a remainder count node", + "code": [ + { + "language": "typescript", + "content": [ + "const node = remainderCountNode();" + ] + } + ] + }, + { + "title": "A remainder array of public keys", + "code": [ + { + "language": "typescript", + "content": [ + "arrayTypeNode(publicKeyTypeNode(), remainderCountNode());" + ] + } + ] + } + ] } ], "unions": [ @@ -2173,7 +3279,49 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a constant discriminator node from a constant value and an optional offset", + "code": [ + { + "language": "typescript", + "content": [ + "const node = constantDiscriminatorNode(constantValueNode(stringTypeNode('utf8'), stringValueNode('Hello')), 64);" + ] + } + ] + }, + { + "title": "An account distinguished by a u32 number equal to 42 at offset 0", + "code": [ + { + "language": "typescript", + "content": [ + "accountNode({", + " discriminators: [constantDiscriminatorNode(constantValueNode(numberTypeNode('u32'), numberValueNode(42)))],", + " // ...", + "});" + ] + } + ] + }, + { + "title": "An instruction distinguished by an 8-byte hash at offset 0", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " discriminators: [", + " constantDiscriminatorNode(constantValueNode(bytesTypeNode(), bytesValueNode('base16', '0011223344556677'))),", + " ],", + " // ...", + "});" + ] + } + ] + } + ] }, { "kind": "fieldDiscriminatorNode", @@ -2202,7 +3350,65 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a field discriminator node from a field name and an optional offset", + "code": [ + { + "language": "typescript", + "content": [ + "const node = fieldDiscriminatorNode('accountState', 64);" + ] + } + ] + }, + { + "title": "An account distinguished by a u32 field at offset 0", + "code": [ + { + "language": "typescript", + "content": [ + "accountNode({", + " data: structTypeNode([", + " structFieldTypeNode({", + " name: 'discriminator',", + " type: numberTypeNode('u32'),", + " defaultValue: numberValueNode(42),", + " defaultValueStrategy: 'omitted',", + " }),", + " // ...", + " ]),", + " discriminators: [fieldDiscriminatorNode('discriminator')],", + " // ...", + "});" + ] + } + ] + }, + { + "title": "An instruction distinguished by an 8-byte argument at offset 0", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " arguments: [", + " instructionArgumentNode({", + " name: 'discriminator',", + " type: fixedSizeTypeNode(bytesTypeNode(), 8),", + " defaultValue: bytesValueNode('base16', '0011223344556677'),", + " defaultValueStrategy: 'omitted',", + " }),", + " // ...", + " ],", + " discriminators: [fieldDiscriminatorNode('discriminator')],", + " // ...", + "});" + ] + } + ] + } + ] }, { "kind": "sizeDiscriminatorNode", @@ -2221,7 +3427,47 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a size discriminator node from a size", + "code": [ + { + "language": "typescript", + "content": [ + "const node = sizeDiscriminatorNode(165);" + ] + } + ] + }, + { + "title": "An account distinguished by its size being equal to 42", + "code": [ + { + "language": "typescript", + "content": [ + "accountNode({", + " discriminators: [sizeDiscriminatorNode(42)],", + " // ...", + "});" + ] + } + ] + }, + { + "title": "An instruction distinguished by its size being equal to 42", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " discriminators: [sizeDiscriminatorNode(42)],", + " // ...", + "});" + ] + } + ] + } + ] } ], "unions": [ @@ -2300,7 +3546,41 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "A fixed 9-decimal SOL amount", + "code": [ + { + "language": "typescript", + "content": [ + "numberTypeNode('u64', 'le', {", + " display: amountNumberDisplayNode({ decimals: numberValueNode(9), unit: stringValueNode('SOL') }),", + "});", + "", + "// 1_100_000_000 => \"1.1 SOL\"" + ] + } + ] + }, + { + "title": "Decimals and unit injected from surrounding account state", + "code": [ + { + "language": "typescript", + "content": [ + "numberTypeNode('u64', 'le', {", + " display: amountNumberDisplayNode({", + " decimals: injectedValueNode({ key: 'decimals' }),", + " unit: injectedValueNode({ key: 'symbol' }),", + " }),", + "});", + "", + "// 1_500_000 with injected decimals 6 and symbol \"USDC\" => \"1.5 USDC\"" + ] + } + ] + } + ] }, { "kind": "dateTimeNumberDisplayNode", @@ -2322,7 +3602,34 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "A Unix timestamp already in seconds", + "code": [ + { + "language": "typescript", + "content": [ + "numberTypeNode('i64', 'le', { display: dateTimeNumberDisplayNode({}) });", + "", + "// 1_761_365_183 => \"2025-10-25T04:06:23.000Z\"" + ] + } + ] + }, + { + "title": "A millisecond timestamp scaled back to seconds", + "code": [ + { + "language": "typescript", + "content": [ + "numberTypeNode('i64', 'le', { display: dateTimeNumberDisplayNode({ ticksPerSecond: 1000 }) });", + "", + "// 1_761_365_183_000 => \"2025-10-25T04:06:23.000Z\"" + ] + } + ] + } + ] }, { "kind": "durationNumberDisplayNode", @@ -2345,7 +3652,34 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "A duration already in seconds", + "code": [ + { + "language": "typescript", + "content": [ + "numberTypeNode('u32', 'le', { display: durationNumberDisplayNode({}) });", + "", + "// 3600 => \"01:00:00\"" + ] + } + ] + }, + { + "title": "A duration in milliseconds scaled back to seconds", + "code": [ + { + "language": "typescript", + "content": [ + "numberTypeNode('u64', 'le', { display: durationNumberDisplayNode({ ticksPerSecond: 1000 }) });", + "", + "// 90_000 => \"00:01:30\"" + ] + } + ] + } + ] }, { "kind": "enumVariantDisplayNode", @@ -2376,7 +3710,40 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Relabelling a struct variant", + "code": [ + { + "language": "typescript", + "content": [ + "enumStructVariantTypeNode(", + " 'buy',", + " structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') })]),", + " undefined,", + " { display: enumVariantDisplayNode({ label: 'Buy' }) },", + ");" + ] + } + ] + }, + { + "title": "Hiding a tuple payload so only the label is shown", + "code": [ + { + "language": "typescript", + "content": [ + "enumTupleVariantTypeNode(", + " 'increment',", + " tupleTypeNode([numberTypeNode('u64')]),", + " undefined,", + " { display: enumVariantDisplayNode({ label: 'Increment', skipInnerData: true }) },", + ");" + ] + } + ] + } + ] }, { "kind": "instructionAccountDisplayNode", @@ -2407,7 +3774,40 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Relabelling an account in the fallback list", + "code": [ + { + "language": "typescript", + "content": [ + "instructionAccountNode({", + " name: 'destination',", + " isSigner: false,", + " isWritable: true,", + " display: instructionAccountDisplayNode({ label: 'To' }),", + "});" + ] + } + ] + }, + { + "title": "Hiding an account once its value is surfaced elsewhere", + "code": [ + { + "language": "typescript", + "content": [ + "instructionAccountNode({", + " name: 'mint',", + " isSigner: false,", + " isWritable: false,", + " display: instructionAccountDisplayNode({ label: 'Token Mint', skip: 'whenInjected' }),", + "});" + ] + } + ] + } + ] }, { "kind": "instructionDisplayNode", @@ -2439,7 +3839,44 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "An intent label plus an interpolated sentence", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " name: 'transferChecked',", + " display: instructionDisplayNode({", + " intent: 'Transfer',", + " interpolatedIntent: 'Transfer ${data.amount} to ${accounts.destination}',", + " }),", + " // ...accounts and arguments", + "});", + "", + "// intent => \"Transfer\"", + "// interpolated => \"Transfer 1.5 USDC to 3Wnd5…5PxJX\"" + ] + } + ] + }, + { + "title": "An intent label only, letting the renderer build the fallback list", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " name: 'closeAccount',", + " display: instructionDisplayNode({ intent: 'Close Account' }),", + " // ...accounts and arguments", + "});" + ] + } + ] + } + ] }, { "kind": "stringDisplayNode", @@ -2473,7 +3910,34 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Displaying the whole string", + "code": [ + { + "language": "typescript", + "content": [ + "stringTypeNode('utf8', { display: stringDisplayNode({}) });", + "", + "// \"SOLANA\" => \"SOLANA\"" + ] + } + ] + }, + { + "title": "Displaying a leading slice", + "code": [ + { + "language": "typescript", + "content": [ + "stringTypeNode('utf8', { display: stringDisplayNode({ sliceStart: 0, sliceEnd: 3 }) });", + "", + "// \"SOLANA\" => \"SOL\"" + ] + } + ] + } + ] }, { "kind": "structFieldDisplayNode", @@ -2528,7 +3992,53 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Relabelling an instruction argument", + "code": [ + { + "language": "typescript", + "content": [ + "instructionArgumentNode({", + " name: 'amount',", + " type: numberTypeNode('u64'),", + " display: structFieldDisplayNode({ label: 'Amount' }),", + "});" + ] + } + ] + }, + { + "title": "Hiding a discriminator argument from the fallback list", + "code": [ + { + "language": "typescript", + "content": [ + "instructionArgumentNode({", + " name: 'discriminator',", + " type: numberTypeNode('u8'),", + " display: structFieldDisplayNode({ skip: 'always' }),", + "});" + ] + } + ] + }, + { + "title": "Flattening a nested struct into its parent with a label prefix", + "code": [ + { + "language": "typescript", + "content": [ + "structFieldTypeNode({", + " name: 'config',", + " type: definedTypeLinkNode('config'),", + " display: structFieldDisplayNode({ flatten: true, flattenPrefix: 'config.' }),", + "});" + ] + } + ] + } + ] } ], "unions": [ @@ -2631,7 +4141,48 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create an account bump value node from an account name", + "code": [ + { + "language": "typescript", + "content": [ + "const node = accountBumpValueNode('associatedTokenAccount');" + ] + } + ] + }, + { + "title": "An instruction argument defaulting to the bump derivation of an instruction account", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " name: 'transfer',", + " accounts: [", + " instructionAccountNode({", + " name: 'associatedTokenAccount',", + " isSigner: false,", + " isWritable: true,", + " }),", + " // ...", + " ],", + " arguments: [", + " instructionArgumentNode({", + " name: 'bump',", + " type: numberTypeNode('u8'),", + " defaultValue: accountBumpValueNode('associatedTokenAccount'),", + " }),", + " // ...", + " ],", + "});" + ] + } + ] + } + ] }, { "kind": "accountFieldValueNode", @@ -2683,7 +4234,46 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create an account value node from an account name", + "code": [ + { + "language": "typescript", + "content": [ + "const node = accountValueNode('mint');" + ] + } + ] + }, + { + "title": "An instruction account defaulting to another account", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " name: 'mint',", + " accounts: [", + " instructionAccountNode({", + " name: 'payer',", + " isSigner: true,", + " isWritable: false,", + " }),", + " instructionAccountNode({", + " name: 'authority',", + " isSigner: false,", + " isWritable: true,", + " defaultValue: accountValueNode('payer'),", + " }),", + " // ...", + " ],", + "});" + ] + } + ] + } + ] }, { "kind": "argumentValueNode", @@ -2702,7 +4292,44 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create an argument value node from an argument name", + "code": [ + { + "language": "typescript", + "content": [ + "const node = argumentValueNode('amount');" + ] + } + ] + }, + { + "title": "An instruction argument defaulting to another argument", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " name: 'mint',", + " arguments: [", + " instructionArgumentNode({", + " name: 'amount',", + " type: numberTypeNode('u64'),", + " }),", + " instructionArgumentNode({", + " name: 'amountToDelegate',", + " type: numberTypeNode('u64'),", + " defaultValue: argumentValueNode('amount'),", + " }),", + " // ...", + " ],", + "});" + ] + } + ] + } + ] }, { "kind": "conditionalValueNode", @@ -2756,7 +4383,62 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a conditional value node from an input object", + "code": [ + { + "language": "typescript", + "content": [ + "const node = conditionalValueNode({", + " condition: argumentValueNode('amount'),", + " value: numberValueNode(0),", + " ifTrue: accountValueNode('mint'),", + " ifFalse: programIdValueNode(),", + "});" + ] + } + ] + }, + { + "title": "An instruction account that defaults to another account if a condition is met", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " name: 'transfer',", + " accounts: [", + " instructionAccountNode({", + " name: 'source',", + " isSigner: false,", + " isWritable: true,", + " }),", + " instructionAccountNode({", + " name: 'destination',", + " isSigner: false,", + " isWritable: true,", + " isOptional: true,", + " defaultValue: conditionalValueNode({", + " condition: argumentValueNode('amount'),", + " value: numberValueNode(0),", + " ifTrue: accountValueNode('source'),", + " }),", + " }),", + " // ...", + " ],", + " arguments: [", + " instructionArgumentNode({", + " name: 'amount',", + " type: numberTypeNode('u64'),", + " }),", + " ],", + "});" + ] + } + ] + } + ] }, { "kind": "identityValueNode", @@ -2764,7 +4446,41 @@ "Refers to the wallet identity providing the instruction context." ], "attributes": [], - "examples": [] + "examples": [ + { + "title": "Create an identity value node", + "code": [ + { + "language": "typescript", + "content": [ + "const node = identityValueNode();" + ] + } + ] + }, + { + "title": "An instruction account defaulting to the identity value", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " name: 'transfer',", + " accounts: [", + " instructionAccountNode({", + " name: 'authority',", + " isSigner: true,", + " isWritable: false,", + " defaultValue: identityValueNode(),", + " }),", + " // ...", + " ],", + "});" + ] + } + ] + } + ] }, { "kind": "payerValueNode", @@ -2772,7 +4488,41 @@ "Refers to the wallet paying for the surrounding transaction." ], "attributes": [], - "examples": [] + "examples": [ + { + "title": "Create a payer value node", + "code": [ + { + "language": "typescript", + "content": [ + "const node = payerValueNode();" + ] + } + ] + }, + { + "title": "An instruction account defaulting to the payer value", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " name: 'transfer',", + " accounts: [", + " instructionAccountNode({", + " name: 'payer',", + " isSigner: true,", + " isWritable: false,", + " defaultValue: payerValueNode(),", + " }),", + " // ...", + " ],", + "});" + ] + } + ] + } + ] }, { "kind": "pdaSeedValueNode", @@ -2801,7 +4551,19 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a PDA seed value node from a name and a value", + "code": [ + { + "language": "typescript", + "content": [ + "const node = pdaSeedValueNode('mint', accountValueNode('mint'));" + ] + } + ] + } + ] }, { "kind": "pdaValueNode", @@ -2844,7 +4606,59 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a PDA value node from a PDA definition and seed values", + "code": [ + { + "language": "typescript", + "content": [ + "const node = pdaValueNode('associatedToken', [", + " pdaSeedValueNode('mint', publicKeyValueNode('G345gmp34svbGxyXuCvKVVHDbqJQ66y65vVrx7m7FmBE')),", + " pdaSeedValueNode('owner', publicKeyValueNode('Nzgr9bYfMRq5768bHfXsXoPTnLWAXgQNosRBxK63jRH')),", + "]);" + ] + } + ] + }, + { + "title": "A PDA value whose seeds point to other accounts", + "code": [ + { + "language": "typescript", + "content": [ + "pdaValueNode('associatedToken', [", + " pdaSeedValueNode('mint', accountValueNode('mint')),", + " pdaSeedValueNode('owner', accountValueNode('authority')),", + "]);" + ] + } + ] + }, + { + "title": "A PDA value with an inlined PDA definition", + "code": [ + { + "language": "typescript", + "content": [ + "const inlinedPdaNode = pdaNode({", + " name: 'associatedToken',", + " seeds: [", + " variablePdaSeedNode('mint', publicKeyTypeNode()),", + " constantPdaSeedNode(publicKeyTypeNode(), publicKeyValueNode('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA')),", + " variablePdaSeedNode('owner', publicKeyTypeNode()),", + " ],", + "});", + "", + "pdaValueNode(inlinedPdaNode, [", + " pdaSeedValueNode('mint', accountValueNode('mint')),", + " pdaSeedValueNode('owner', accountValueNode('authority')),", + "]);" + ] + } + ] + } + ] }, { "kind": "programIdValueNode", @@ -2852,7 +4666,19 @@ "Refers to the program ID of the surrounding instruction." ], "attributes": [], - "examples": [] + "examples": [ + { + "title": "Create a program id value node", + "code": [ + { + "language": "typescript", + "content": [ + "const node = programIdValueNode();" + ] + } + ] + } + ] }, { "kind": "resolverValueNode", @@ -2896,7 +4722,26 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a resolver value node from a name and options", + "code": [ + { + "language": "typescript", + "content": [ + "const node = resolverValueNode('resolveCustomTokenProgram', {", + " docs: [", + " 'If the mint account has more than 0 decimals and the ',", + " 'delegated amount is greater than zero, then we use our ',", + " 'own custom token program. Otherwise, we use Token 2022.',", + " ],", + " dependsOn: [accountValueNode('mint'), argumentValueNode('delegatedAmount')],", + "});" + ] + } + ] + } + ] } ], "unions": [ @@ -3497,7 +5342,57 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "A fixed-size account", + "code": [ + { + "language": "typescript", + "content": [ + "const node = accountNode({", + " name: 'token',", + " data: structTypeNode([", + " structFieldTypeNode({ name: 'mint', type: publicKeyTypeNode() }),", + " structFieldTypeNode({ name: 'owner', type: publicKeyTypeNode() }),", + " structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') }),", + " ]),", + " discriminators: [sizeDiscriminatorNode(72)],", + " size: 72,", + "});" + ] + } + ] + }, + { + "title": "An account with a linked PDA", + "code": [ + { + "language": "typescript", + "content": [ + "programNode({", + " name: 'myProgram',", + " accounts: [", + " accountNode({", + " name: 'token',", + " data: structTypeNode([structFieldTypeNode({ name: 'authority', type: publicKeyTypeNode() })]),", + " pda: pdaLinkNode('myPda'),", + " }),", + " ],", + " pdas: [", + " pdaNode({", + " name: 'myPda',", + " seeds: [", + " constantPdaSeedNodeFromString('utf8', 'token'),", + " variablePdaSeedNode('authority', publicKeyTypeNode()),", + " ],", + " }),", + " ],", + "});" + ] + } + ] + } + ] }, { "kind": "constantNode", @@ -3546,7 +5441,43 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Numeric Constant", + "code": [ + { + "language": "typescript", + "content": [ + "const node = constantNode('maxSize', numberTypeNode('u32'), numberValueNode(100));" + ] + } + ] + }, + { + "title": "Bytes Constant", + "code": [ + { + "language": "typescript", + "content": [ + "const node = constantNode('seedPrefix', bytesTypeNode(), bytesValueNode('base16', '74657374'));" + ] + } + ] + }, + { + "title": "With Documentation", + "code": [ + { + "language": "typescript", + "content": [ + "const node = constantNode('maxItems', numberTypeNode('u64'), numberValueNode(1000), [", + " 'The maximum number of items allowed.',", + "]);" + ] + } + ] + } + ] }, { "kind": "definedTypeNode", @@ -3585,7 +5516,26 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a defined type node from an input object", + "code": [ + { + "language": "typescript", + "content": [ + "const node = definedTypeNode({", + " name: 'person',", + " docs: ['This type describes a Person.'],", + " type: structTypeNode([", + " structFieldTypeNode({ name: 'name', type: stringTypeNode('utf8') }),", + " structFieldTypeNode({ name: 'age', type: numberTypeNode('u8') }),", + " ]),", + "});" + ] + } + ] + } + ] }, { "kind": "errorNode", @@ -3633,7 +5583,23 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create an error node from an input object", + "code": [ + { + "language": "typescript", + "content": [ + "const node = errorNode({", + " name: 'invalidAmountArgument',", + " code: 1,", + " message: 'The amount argument is invalid.',", + "});" + ] + } + ] + } + ] }, { "kind": "eventNode", @@ -3686,7 +5652,46 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "An event with a struct payload", + "code": [ + { + "language": "typescript", + "content": [ + "eventNode({", + " name: 'transferEvent',", + " data: structTypeNode([", + " structFieldTypeNode({ name: 'authority', type: publicKeyTypeNode() }),", + " structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') }),", + " ]),", + "});" + ] + } + ] + }, + { + "title": "An event with a hidden prefix discriminator", + "code": [ + { + "language": "typescript", + "content": [ + "eventNode({", + " name: 'transferEvent',", + " data: hiddenPrefixTypeNode(structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') })]), [", + " constantValueNode(fixedSizeTypeNode(bytesTypeNode(), 8), bytesValueNode('base16', '0102030405060708')),", + " ]),", + " discriminators: [", + " constantDiscriminatorNode(", + " constantValueNode(fixedSizeTypeNode(bytesTypeNode(), 8), bytesValueNode('base16', '0102030405060708')),", + " ),", + " ],", + "});" + ] + } + ] + } + ] }, { "kind": "instructionAccountNode", @@ -3783,7 +5788,41 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "An optional account", + "code": [ + { + "language": "typescript", + "content": [ + "instructionAccountNode({", + " name: 'freezeAuthority',", + " isWritable: false,", + " isSigner: false,", + " isOptional: true,", + " docs: ['The freeze authority to set on the asset, if any.'],", + "});" + ] + } + ] + }, + { + "title": "An optional signer account", + "code": [ + { + "language": "typescript", + "content": [ + "instructionAccountNode({", + " name: 'owner',", + " isWritable: true,", + " isSigner: 'either',", + " docs: ['The owner of the asset. The owner must only sign the transaction if the asset is being updated.'],", + "});" + ] + } + ] + } + ] }, { "kind": "instructionArgumentNode", @@ -3855,7 +5894,39 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "An argument with a default value", + "code": [ + { + "language": "typescript", + "content": [ + "instructionArgumentNode({", + " name: 'amount',", + " type: numberTypeNode('u64'),", + " defaultValue: numberValueNode(0),", + "});" + ] + } + ] + }, + { + "title": "An argument with an omitted default value", + "code": [ + { + "language": "typescript", + "content": [ + "instructionArgumentNode({", + " name: 'instructionDiscriminator',", + " type: numberTypeNode('u8'),", + " defaultValue: numberValueNode(42),", + " defaultValueStrategy: 'omitted',", + "});" + ] + } + ] + } + ] }, { "kind": "instructionByteDeltaNode", @@ -3893,7 +5964,41 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "A byte delta that represents a new account", + "code": [ + { + "language": "typescript", + "content": [ + "instructionByteDeltaNode(accountLinkNode('token'));" + ] + } + ] + }, + { + "title": "A byte delta that represents an account deletion", + "code": [ + { + "language": "typescript", + "content": [ + "instructionByteDeltaNode(accountLinkNode('token'), { subtract: true });" + ] + } + ] + }, + { + "title": "A byte delta that uses an argument value to increase the space of an account", + "code": [ + { + "language": "typescript", + "content": [ + "instructionByteDeltaNode(argumentValueNode('additionalSpace'), { withHeader: false });" + ] + } + ] + } + ] }, { "kind": "instructionNode", @@ -4081,7 +6186,194 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "An instruction with a u8 discriminator", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " name: 'increment',", + " accounts: [", + " instructionAccountNode({ name: 'counter', isWritable: true, isSigner: true }),", + " instructionAccountNode({ name: 'authority', isWritable: false, isSigner: false }),", + " ],", + " arguments: [", + " instructionArgumentNode({", + " name: 'discriminator',", + " type: numberTypeNode('u8'),", + " defaultValue: numberValueNode(42),", + " defaultValueStrategy: 'omitted',", + " }),", + " ],", + "});" + ] + } + ] + }, + { + "title": "An instruction that creates a new account", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " name: 'createCounter',", + " accounts: [", + " instructionAccountNode({ name: 'counter', isWritable: true, isSigner: true }),", + " instructionAccountNode({ name: 'authority', isWritable: false, isSigner: false }),", + " ],", + " byteDeltas: [instructionByteDeltaNode(accountLinkNode('counter'))],", + "});" + ] + } + ] + }, + { + "title": "An instruction with omitted optional accounts", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " name: 'initialize',", + " accounts: [", + " instructionAccountNode({ name: 'counter', isWritable: true, isSigner: true }),", + " instructionAccountNode({ name: 'authority', isWritable: false, isSigner: false }),", + " instructionAccountNode({ name: 'freezeAuthority', isWritable: false, isSigner: false, isOptional: true }),", + " ],", + " optionalAccountStrategy: 'omitted',", + "});" + ] + } + ] + }, + { + "title": "An instruction with remaining signers", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " name: 'multisigIncrement',", + " accounts: [instructionAccountNode({ name: 'counter', isWritable: true, isSigner: false })],", + " remainingAccounts: [instructionRemainingAccountsNode(argumentValueNode('authorities'), { isSigner: true })],", + "});" + ] + } + ] + }, + { + "title": "An instruction with nested versioned instructions", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " name: 'increment',", + " accounts: [", + " instructionAccountNode({ name: 'counter', isWritable: true, isSigner: 'either' }),", + " instructionAccountNode({ name: 'authority', isWritable: false, isSigner: true }),", + " ],", + " arguments: [", + " instructionArgumentNode({ name: 'version', type: numberTypeNode('u8') }),", + " instructionArgumentNode({ name: 'amount', type: numberTypeNode('u8') }),", + " ],", + " subInstructions: [", + " instructionNode({", + " name: 'incrementV1',", + " accounts: [instructionAccountNode({ name: 'counter', isWritable: true, isSigner: true })],", + " arguments: [", + " instructionArgumentNode({", + " name: 'version',", + " type: numberTypeNode('u8'),", + " defaultValue: numberValueNode(0),", + " defaultValueStrategy: 'omitted',", + " }),", + " instructionArgumentNode({ name: 'amount', type: numberTypeNode('u8') }),", + " ],", + " }),", + " instructionNode({", + " name: 'incrementV2',", + " accounts: [", + " instructionAccountNode({ name: 'counter', isWritable: true, isSigner: false }),", + " instructionAccountNode({ name: 'authority', isWritable: false, isSigner: true }),", + " ],", + " arguments: [", + " instructionArgumentNode({", + " name: 'version',", + " type: numberTypeNode('u8'),", + " defaultValue: numberValueNode(1),", + " defaultValueStrategy: 'omitted',", + " }),", + " instructionArgumentNode({ name: 'amount', type: numberTypeNode('u8') }),", + " ],", + " }),", + " ],", + "});" + ] + } + ] + }, + { + "title": "A deprecated instruction", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " name: 'oldIncrement',", + " status: instructionStatusNode(", + " 'deprecated',", + " 'Use the `increment` instruction instead. This will be removed in v3.0.0.',", + " ),", + " accounts: [instructionAccountNode({ name: 'counter', isWritable: true, isSigner: false })],", + " arguments: [instructionArgumentNode({ name: 'amount', type: numberTypeNode('u8') })],", + "});" + ] + } + ] + }, + { + "title": "An archived instruction", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " name: 'legacyTransfer',", + " status: instructionStatusNode(", + " 'archived',", + " 'This instruction was removed in v2.0.0. It is kept here for historical parsing.',", + " ),", + " accounts: [", + " instructionAccountNode({ name: 'source', isWritable: true, isSigner: true }),", + " instructionAccountNode({ name: 'destination', isWritable: true, isSigner: false }),", + " ],", + " arguments: [instructionArgumentNode({ name: 'amount', type: numberTypeNode('u64') })],", + "});" + ] + } + ] + }, + { + "title": "A draft instruction", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " name: 'experimentalFeature',", + " status: instructionStatusNode('draft', 'This instruction is under development and may change.'),", + " accounts: [instructionAccountNode({ name: 'config', isWritable: true, isSigner: true })],", + " arguments: [],", + "});" + ] + } + ] + } + ] }, { "kind": "instructionRemainingAccountsNode", @@ -4157,7 +6449,51 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Optional remaining signers", + "code": [ + { + "language": "typescript", + "content": [ + "instructionRemainingAccountsNode(argumentValueNode('authorities'), {", + " isSigner: true,", + " isOptional: true,", + "});" + ] + } + ] + }, + { + "title": "Remaining accounts that may or may not be signers", + "code": [ + { + "language": "typescript", + "content": [ + "instructionRemainingAccountsNode(argumentValueNode('authorities'), {", + " isSigner: 'either',", + "});" + ] + } + ] + }, + { + "title": "Remaining accounts using a resolver", + "code": [ + { + "language": "typescript", + "content": [ + "instructionRemainingAccountsNode(", + " resolverValueNode('resolveTransferRemainingAccounts', {", + " docs: ['Provide authorities as remaining accounts if and only if the asset has a multisig set up.'],", + " dependsOn: [argumentValueNode('hasMultisig'), argumentValueNode('authorities')],", + " }),", + ");" + ] + } + ] + } + ] }, { "kind": "instructionStatusNode", @@ -4186,7 +6522,87 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "A live instruction (no status needed)", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " name: 'transfer',", + " accounts: [...],", + " arguments: [...],", + "});" + ] + } + ] + }, + { + "title": "A deprecated instruction", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " name: 'oldTransfer',", + " status: instructionStatusNode('deprecated', 'Use the `transfer` instruction instead. This will be removed in v3.0.0.'),", + " accounts: [...],", + " arguments: [...],", + "});" + ] + } + ] + }, + { + "title": "An archived instruction", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " name: 'legacyTransfer',", + " status: instructionStatusNode('archived', 'This instruction was removed in v2.0.0. It is kept here for historical parsing.'),", + " accounts: [...],", + " arguments: [...],", + "});" + ] + } + ] + }, + { + "title": "A draft instruction", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " name: 'experimentalFeature',", + " status: instructionStatusNode('draft', 'This instruction is under development and may change.'),", + " accounts: [...],", + " arguments: [...],", + "});" + ] + } + ] + }, + { + "title": "Status without a message", + "code": [ + { + "language": "typescript", + "content": [ + "instructionNode({", + " name: 'someInstruction',", + " status: instructionStatusNode('deprecated'),", + " accounts: [...],", + " arguments: [...],", + "});" + ] + } + ] + } + ] }, { "kind": "pdaNode", @@ -4238,7 +6654,41 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "A PDA with constant and variable seeds", + "code": [ + { + "language": "typescript", + "content": [ + "pdaNode({", + " name: 'ticket',", + " seeds: [", + " constantPdaSeedNodeFromString('utf8', 'raffles'),", + " variablePdaSeedNode('raffle', publicKeyTypeNode()),", + " constantPdaSeedNodeFromString('utf8', 'tickets'),", + " variablePdaSeedNode('ticketNumber', numberTypeNode('u32')),", + " ],", + "});" + ] + } + ] + }, + { + "title": "A PDA with no seeds", + "code": [ + { + "language": "typescript", + "content": [ + "pdaNode({", + " name: 'seedlessPda',", + " seeds: [],", + "});" + ] + } + ] + } + ] }, { "kind": "pluginNode", @@ -4418,7 +6868,29 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "Create a program node from an input object", + "code": [ + { + "language": "typescript", + "content": [ + "const node = programNode({", + " name: 'counter',", + " publicKey: '7ovtg4pFqjQdSwFAUCu8gTnh5thZHzAyJFXy3Ssnj3yK',", + " version: '1.42.6',", + " accounts: [],", + " instructions: [],", + " definedTypes: [],", + " pdas: [],", + " events: [],", + " errors: [],", + "});" + ] + } + ] + } + ] }, { "kind": "providedNode", @@ -4499,7 +6971,40 @@ ] } ], - "examples": [] + "examples": [ + { + "title": "A root node with a single program", + "code": [ + { + "language": "typescript", + "content": [ + "const node = rootNode(", + " programNode({", + " name: 'counter',", + " publicKey: '2R3Ui2TVUUCyGcZdopxJauk8ZBzgAaHHZCVUhm5ifPaC',", + " version: '1.0.0',", + " accounts: [", + " accountNode({", + " name: 'counter',", + " data: structTypeNode([", + " structFieldTypeNode({ name: 'authority', type: publicKeyTypeNode() }),", + " structFieldTypeNode({ name: 'value', type: numberTypeNode('u32') }),", + " ]),", + " }),", + " ],", + " instructions: [", + " instructionNode({ name: 'create' /* ... */ }),", + " instructionNode({ name: 'increment' /* ... */ }),", + " instructionNode({ name: 'transferAuthority' /* ... */ }),", + " instructionNode({ name: 'delete' /* ... */ }),", + " ],", + " }),", + ");" + ] + } + ] + } + ] } ], "unions": [