@metaplex-foundation/kinobi 0.5.0 → 0.7.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/dist/cjs/nodes/InstructionNode.js +53 -15
  2. package/dist/cjs/nodes/InstructionNode.js.map +1 -1
  3. package/dist/cjs/renderers/js/GetJavaScriptRenderMapVisitor.js +84 -28
  4. package/dist/cjs/renderers/js/GetJavaScriptRenderMapVisitor.js.map +1 -1
  5. package/dist/cjs/renderers/js/GetJavaScriptTypeManifestVisitor.js +3 -0
  6. package/dist/cjs/renderers/js/GetJavaScriptTypeManifestVisitor.js.map +1 -1
  7. package/dist/cjs/renderers/js/GetJavaScriptValidatorBagVisitor.js +2 -0
  8. package/dist/cjs/renderers/js/GetJavaScriptValidatorBagVisitor.js.map +1 -1
  9. package/dist/cjs/renderers/js/templates/instructionsPage.njk +11 -24
  10. package/dist/cjs/renderers/js/templates/instructionsPageAccountMetas.njk +8 -51
  11. package/dist/cjs/renderers/js/templates/instructionsPageArgs.njk +34 -5
  12. package/dist/cjs/renderers/js/templates/instructionsPageResolvedInputs.njk +63 -0
  13. package/dist/cjs/renderers/js/templates/programsPage.njk +12 -2
  14. package/dist/cjs/visitors/BaseNodeOrNullVisitor.js +6 -1
  15. package/dist/cjs/visitors/BaseNodeOrNullVisitor.js.map +1 -1
  16. package/dist/cjs/visitors/BaseNodeVisitor.js +6 -1
  17. package/dist/cjs/visitors/BaseNodeVisitor.js.map +1 -1
  18. package/dist/cjs/visitors/BaseVoidVisitor.js +2 -0
  19. package/dist/cjs/visitors/BaseVoidVisitor.js.map +1 -1
  20. package/dist/cjs/visitors/aggregators/GetDefaultValidatorBagVisitor.js +32 -2
  21. package/dist/cjs/visitors/aggregators/GetDefaultValidatorBagVisitor.js.map +1 -1
  22. package/dist/cjs/visitors/aggregators/GetNodeInlineStringVisitor.js +4 -2
  23. package/dist/cjs/visitors/aggregators/GetNodeInlineStringVisitor.js.map +1 -1
  24. package/dist/cjs/visitors/aggregators/GetNodeTreeStringVisitor.js +6 -0
  25. package/dist/cjs/visitors/aggregators/GetNodeTreeStringVisitor.js.map +1 -1
  26. package/dist/cjs/visitors/aggregators/GetResolvedInstructionInputsVisitor.js +201 -0
  27. package/dist/cjs/visitors/aggregators/GetResolvedInstructionInputsVisitor.js.map +1 -0
  28. package/dist/cjs/visitors/aggregators/index.js +1 -1
  29. package/dist/cjs/visitors/aggregators/index.js.map +1 -1
  30. package/dist/cjs/visitors/transformers/AutoSetAnchorDiscriminatorsVisitor.js +1 -1
  31. package/dist/cjs/visitors/transformers/AutoSetAnchorDiscriminatorsVisitor.js.map +1 -1
  32. package/dist/cjs/visitors/transformers/CreateSubInstructionsFromEnumArgsVisitor.js +2 -2
  33. package/dist/cjs/visitors/transformers/CreateSubInstructionsFromEnumArgsVisitor.js.map +1 -1
  34. package/dist/cjs/visitors/transformers/FlattenInstructionArgsStructVisitor.js +1 -1
  35. package/dist/cjs/visitors/transformers/FlattenInstructionArgsStructVisitor.js.map +1 -1
  36. package/dist/cjs/visitors/transformers/SetInstructionAccountDefaultValuesVisitor.js +1 -1
  37. package/dist/cjs/visitors/transformers/SetInstructionAccountDefaultValuesVisitor.js.map +1 -1
  38. package/dist/cjs/visitors/transformers/SetInstructionDiscriminatorsVisitor.js +1 -1
  39. package/dist/cjs/visitors/transformers/SetInstructionDiscriminatorsVisitor.js.map +1 -1
  40. package/dist/cjs/visitors/transformers/UpdateInstructionsVisitor.js +8 -5
  41. package/dist/cjs/visitors/transformers/UpdateInstructionsVisitor.js.map +1 -1
  42. package/dist/cjs/visitors/transformers/UseCustomInstructionSerializerVisitor.js +1 -1
  43. package/dist/cjs/visitors/transformers/UseCustomInstructionSerializerVisitor.js.map +1 -1
  44. package/dist/types/idl/IdlInstruction.d.ts +0 -1
  45. package/dist/types/nodes/InstructionNode.d.ts +53 -14
  46. package/dist/types/renderers/js/GetJavaScriptRenderMapVisitor.d.ts +10 -2
  47. package/dist/types/renderers/js/GetJavaScriptTypeManifestVisitor.d.ts +1 -0
  48. package/dist/types/visitors/aggregators/GetResolvedInstructionInputsVisitor.d.ts +41 -0
  49. package/dist/types/visitors/aggregators/index.d.ts +1 -1
  50. package/dist/types/visitors/transformers/UpdateInstructionsVisitor.d.ts +7 -2
  51. package/package.json +1 -1
  52. package/src/idl/IdlInstruction.ts +0 -1
  53. package/src/nodes/InstructionNode.ts +99 -21
  54. package/src/renderers/js/GetJavaScriptRenderMapVisitor.ts +106 -37
  55. package/src/renderers/js/GetJavaScriptTypeManifestVisitor.ts +6 -0
  56. package/src/renderers/js/GetJavaScriptValidatorBagVisitor.ts +2 -0
  57. package/src/renderers/js/templates/instructionsPage.njk +11 -24
  58. package/src/renderers/js/templates/instructionsPageAccountMetas.njk +8 -51
  59. package/src/renderers/js/templates/instructionsPageArgs.njk +34 -5
  60. package/src/renderers/js/templates/instructionsPageResolvedInputs.njk +63 -0
  61. package/src/renderers/js/templates/programsPage.njk +12 -2
  62. package/src/visitors/BaseNodeOrNullVisitor.ts +5 -0
  63. package/src/visitors/BaseNodeVisitor.ts +5 -0
  64. package/src/visitors/BaseVoidVisitor.ts +1 -0
  65. package/src/visitors/aggregators/GetDefaultValidatorBagVisitor.ts +48 -2
  66. package/src/visitors/aggregators/GetNodeInlineStringVisitor.ts +3 -2
  67. package/src/visitors/aggregators/GetNodeTreeStringVisitor.ts +6 -0
  68. package/src/visitors/aggregators/GetResolvedInstructionInputsVisitor.ts +275 -0
  69. package/src/visitors/aggregators/index.ts +1 -1
  70. package/src/visitors/transformers/AutoSetAnchorDiscriminatorsVisitor.ts +1 -0
  71. package/src/visitors/transformers/CreateSubInstructionsFromEnumArgsVisitor.ts +2 -0
  72. package/src/visitors/transformers/FlattenInstructionArgsStructVisitor.ts +1 -0
  73. package/src/visitors/transformers/SetInstructionAccountDefaultValuesVisitor.ts +1 -0
  74. package/src/visitors/transformers/SetInstructionDiscriminatorsVisitor.ts +1 -0
  75. package/src/visitors/transformers/UpdateInstructionsVisitor.ts +19 -14
  76. package/src/visitors/transformers/UseCustomInstructionSerializerVisitor.ts +1 -0
  77. package/dist/cjs/visitors/aggregators/GetResolvedInstructionAccountsVisitor.js +0 -123
  78. package/dist/cjs/visitors/aggregators/GetResolvedInstructionAccountsVisitor.js.map +0 -1
  79. package/dist/types/visitors/aggregators/GetResolvedInstructionAccountsVisitor.d.ts +0 -18
  80. package/src/visitors/aggregators/GetResolvedInstructionAccountsVisitor.ts +0 -155
@@ -1,7 +1,7 @@
1
1
  import type { ConfigureOptions } from 'nunjucks';
2
2
  import { Options as PrettierOptions } from 'prettier';
3
3
  import * as nodes from '../../nodes';
4
- import { Visitor, BaseThrowVisitor, ResolvedInstructionAccount, Dependency } from '../../visitors';
4
+ import { Visitor, BaseThrowVisitor, Dependency, ResolvedInstructionAccount } from '../../visitors';
5
5
  import { RenderMap } from '../RenderMap';
6
6
  import { JavaScriptTypeManifest } from './GetJavaScriptTypeManifestVisitor';
7
7
  import { JavaScriptImportMap } from './JavaScriptImportMap';
@@ -11,12 +11,16 @@ export type GetJavaScriptRenderMapOptions = {
11
11
  dependencyMap?: Record<Dependency, string>;
12
12
  typeManifestVisitor?: Visitor<JavaScriptTypeManifest> & {
13
13
  setImportStrategy: (importStrategy: 'all' | 'looseOnly' | 'strictOnly') => void;
14
+ setDefinedName: (definedName: {
15
+ strict: string;
16
+ loose: string;
17
+ } | null) => void;
14
18
  };
15
19
  };
16
20
  export declare class GetJavaScriptRenderMapVisitor extends BaseThrowVisitor<RenderMap> {
17
21
  readonly options: Required<GetJavaScriptRenderMapOptions>;
18
22
  private program;
19
- private resolvedInstructionAccountVisitor;
23
+ private resolvedInstructionInputVisitor;
20
24
  constructor(options?: GetJavaScriptRenderMapOptions);
21
25
  visitRoot(root: nodes.RootNode): RenderMap;
22
26
  visitProgram(program: nodes.ProgramNode): RenderMap;
@@ -25,6 +29,10 @@ export declare class GetJavaScriptRenderMapVisitor extends BaseThrowVisitor<Rend
25
29
  visitDefinedType(definedType: nodes.DefinedTypeNode): RenderMap;
26
30
  get typeManifestVisitor(): Visitor<JavaScriptTypeManifest> & {
27
31
  setImportStrategy: (importStrategy: "all" | "looseOnly" | "strictOnly") => void;
32
+ setDefinedName: (definedName: {
33
+ strict: string;
34
+ loose: string;
35
+ } | null) => void;
28
36
  };
29
37
  protected getInstructionAccountType(account: ResolvedInstructionAccount): string;
30
38
  protected getInstructionAccountImports(accounts: ResolvedInstructionAccount[]): JavaScriptImportMap;
@@ -14,6 +14,7 @@ export declare class GetJavaScriptTypeManifestVisitor implements Visitor<JavaScr
14
14
  private definedName;
15
15
  constructor(serializerVariable?: string);
16
16
  setImportStrategy(strategy: GetJavaScriptTypeManifestVisitor['importStrategy']): void;
17
+ setDefinedName(definedName: GetJavaScriptTypeManifestVisitor['definedName']): void;
17
18
  visitRoot(): JavaScriptTypeManifest;
18
19
  visitProgram(): JavaScriptTypeManifest;
19
20
  visitAccount(account: nodes.AccountNode): JavaScriptTypeManifest;
@@ -0,0 +1,41 @@
1
+ import type * as nodes from '../../nodes';
2
+ import { BaseThrowVisitor } from '../BaseThrowVisitor';
3
+ type InstructionNodeInput = ({
4
+ kind: 'arg';
5
+ } & InstructionNodeArg) | ({
6
+ kind: 'account';
7
+ } & nodes.InstructionNodeAccount);
8
+ type InstructionNodeArg = {
9
+ name: string;
10
+ defaultsTo: nodes.InstructionNodeArgDefaults;
11
+ };
12
+ export type ResolvedInstructionAccount = nodes.InstructionNodeAccount & {
13
+ kind: 'account';
14
+ isPda: boolean;
15
+ dependsOn: nodes.InstructionNodeInputDependency[];
16
+ resolvedIsSigner: boolean | 'either';
17
+ resolvedIsOptional: boolean;
18
+ };
19
+ export type ResolvedInstructionArg = InstructionNodeArg & {
20
+ kind: 'arg';
21
+ dependsOn: nodes.InstructionNodeInputDependency[];
22
+ };
23
+ export type ResolvedInstructionInput = ResolvedInstructionAccount | ResolvedInstructionArg;
24
+ export declare class GetResolvedInstructionInputsVisitor extends BaseThrowVisitor<ResolvedInstructionInput[]> {
25
+ protected stack: InstructionNodeInput[];
26
+ protected resolved: ResolvedInstructionInput[];
27
+ protected visitedAccounts: Map<string, ResolvedInstructionAccount>;
28
+ protected visitedArgs: Map<string, ResolvedInstructionArg>;
29
+ protected error: string | null;
30
+ getError(): string | null;
31
+ visitInstruction(instruction: nodes.InstructionNode): ResolvedInstructionInput[];
32
+ resolveInstructionInput(instruction: nodes.InstructionNode, input: InstructionNodeInput): void;
33
+ resolveInstructionAccount(instruction: nodes.InstructionNode, account: nodes.InstructionNodeAccount & {
34
+ kind: 'account';
35
+ }): ResolvedInstructionAccount;
36
+ resolveInstructionArg(instruction: nodes.InstructionNode, arg: InstructionNodeArg & {
37
+ kind: 'arg';
38
+ }): ResolvedInstructionArg;
39
+ resolveInstructionDependencies(instruction: nodes.InstructionNode, parent: InstructionNodeInput, dependencies: nodes.InstructionNodeInputDependency[]): void;
40
+ }
41
+ export {};
@@ -3,4 +3,4 @@ export * from './GetDefaultValidatorBagVisitor';
3
3
  export * from './GetDefinedTypeHistogramVisitor';
4
4
  export * from './GetNodeInlineStringVisitor';
5
5
  export * from './GetNodeTreeStringVisitor';
6
- export * from './GetResolvedInstructionAccountsVisitor';
6
+ export * from './GetResolvedInstructionInputsVisitor';
@@ -1,11 +1,12 @@
1
1
  import * as nodes from '../../nodes';
2
+ import { Dependency } from '../Dependency';
2
3
  import { InstructionNodeAccountDefaultsInput } from './SetInstructionAccountDefaultValuesVisitor';
3
4
  import { NodeTransformer, TransformNodesVisitor } from './TransformNodesVisitor';
4
5
  export type InstructionUpdates = NodeTransformer<nodes.InstructionNode> | {
5
6
  delete: true;
6
7
  } | (InstructionMetadataUpdates & {
7
- accounts?: InstructionAccountUpdates;
8
8
  args?: Record<string, string>;
9
+ extraArgs?: nodes.TypeStructNode | nodes.TypeDefinedLinkNode | null;
9
10
  });
10
11
  export type InstructionMetadataUpdates = Partial<Omit<nodes.InstructionNodeMetadata, 'bytesCreatedOnChain'> & {
11
12
  bytesCreatedOnChain: InstructionNodeBytesCreatedOnChainInput | null;
@@ -25,8 +26,12 @@ type InstructionNodeBytesCreatedOnChainInput = {
25
26
  } | {
26
27
  kind: 'account';
27
28
  name: string;
28
- dependency?: string;
29
+ dependency?: Dependency;
29
30
  includeHeader?: boolean;
31
+ } | {
32
+ kind: 'resolver';
33
+ name: string;
34
+ dependency?: Dependency;
30
35
  };
31
36
  export declare class UpdateInstructionsVisitor extends TransformNodesVisitor {
32
37
  readonly map: Record<string, InstructionUpdates>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metaplex-foundation/kinobi",
3
- "version": "0.5.0",
3
+ "version": "0.7.0-alpha.0",
4
4
  "description": "Generate powerful clients for your Solana programs",
5
5
  "main": "dist/cjs/index.js",
6
6
  "types": "dist/types/index.d.ts",
@@ -17,7 +17,6 @@ export type IdlInstructionAccount = {
17
17
  isOptional?: boolean;
18
18
  optional?: boolean;
19
19
  desc?: string;
20
- pdaBumpArg?: string;
21
20
  };
22
21
 
23
22
  export type IdlInstructionArg = {
@@ -17,6 +17,7 @@ export type InstructionNodeMetadata = {
17
17
  docs: string[];
18
18
  internal: boolean;
19
19
  bytesCreatedOnChain: InstructionNodeBytesCreatedOnChain | null;
20
+ argDefaults: Record<string, InstructionNodeArgDefaults>;
20
21
  };
21
22
 
22
23
  export type InstructionNodeAccount = {
@@ -26,10 +27,28 @@ export type InstructionNodeAccount = {
26
27
  isOptional: boolean;
27
28
  description: string;
28
29
  defaultsTo: InstructionNodeAccountDefaults | null;
29
- pdaBumpArg: string | null;
30
30
  };
31
31
 
32
+ export type InstructionNodeInputDependency = {
33
+ kind: 'account' | 'arg';
34
+ name: string;
35
+ };
36
+
37
+ export type InstructionNodeArgDefaults =
38
+ | { kind: 'arg'; name: string }
39
+ | { kind: 'account'; name: string }
40
+ | { kind: 'accountBump'; name: string }
41
+ | { kind: 'value'; value: ValueNode }
42
+ | {
43
+ kind: 'resolver';
44
+ name: string;
45
+ dependency: Dependency;
46
+ dependsOn: InstructionNodeInputDependency[];
47
+ };
48
+
32
49
  export type InstructionNodeAccountDefaults =
50
+ | { kind: 'programId' }
51
+ | { kind: 'program'; program: { name: string; publicKey: string } }
33
52
  | { kind: 'publicKey'; publicKey: string }
34
53
  | { kind: 'account'; name: string }
35
54
  | { kind: 'identity' }
@@ -40,8 +59,14 @@ export type InstructionNodeAccountDefaults =
40
59
  dependency: Dependency;
41
60
  seeds: Record<string, InstructionNodeAccountDefaultsSeed>;
42
61
  }
43
- | { kind: 'program'; program: { name: string; publicKey: string } }
44
- | { kind: 'programId' };
62
+ | {
63
+ kind: 'resolver';
64
+ name: string;
65
+ dependency: Dependency;
66
+ resolvedIsSigner: boolean | 'either';
67
+ resolvedIsOptional: boolean;
68
+ dependsOn: InstructionNodeInputDependency[];
69
+ };
45
70
 
46
71
  export type InstructionNodeAccountDefaultsSeed =
47
72
  | { kind: 'account'; name: string }
@@ -54,9 +79,10 @@ export type InstructionNodeBytesCreatedOnChain =
54
79
  | {
55
80
  kind: 'account';
56
81
  name: string;
57
- dependency: string;
82
+ dependency: Dependency;
58
83
  includeHeader: boolean;
59
- };
84
+ }
85
+ | { kind: 'resolver'; name: string; dependency: Dependency };
60
86
 
61
87
  export class InstructionNode implements Visitable {
62
88
  readonly nodeClass = 'InstructionNode' as const;
@@ -67,12 +93,15 @@ export class InstructionNode implements Visitable {
67
93
 
68
94
  readonly args: TypeStructNode | TypeDefinedLinkNode;
69
95
 
96
+ readonly extraArgs: TypeStructNode | TypeDefinedLinkNode | null;
97
+
70
98
  readonly subInstructions: InstructionNode[];
71
99
 
72
100
  constructor(
73
101
  metadata: InstructionNodeMetadata,
74
102
  accounts: InstructionNodeAccount[],
75
103
  args: InstructionNode['args'],
104
+ extraArgs: InstructionNode['extraArgs'],
76
105
  subInstructions: InstructionNode[]
77
106
  ) {
78
107
  const bytes = metadata.bytesCreatedOnChain;
@@ -83,6 +112,21 @@ export class InstructionNode implements Visitable {
83
112
  bytes && 'name' in bytes
84
113
  ? { ...bytes, name: mainCase(bytes.name) }
85
114
  : bytes,
115
+ argDefaults: Object.fromEntries(
116
+ Object.entries(metadata.argDefaults).map(([key, value]) => {
117
+ const newValue = { ...value };
118
+ if ('name' in newValue) {
119
+ newValue.name = mainCase(newValue.name);
120
+ }
121
+ if (newValue.kind === 'resolver') {
122
+ newValue.dependsOn = newValue.dependsOn.map((dep) => ({
123
+ ...dep,
124
+ name: mainCase(dep.name),
125
+ }));
126
+ }
127
+ return [mainCase(key), newValue];
128
+ })
129
+ ),
86
130
  };
87
131
  this.accounts = accounts.map((account) => {
88
132
  const { defaultsTo } = account;
@@ -100,10 +144,17 @@ export class InstructionNode implements Visitable {
100
144
  : { ...seed, name: mainCase(seed.name) },
101
145
  ])
102
146
  );
147
+ } else if (defaultsTo?.kind === 'resolver') {
148
+ defaultsTo.name = mainCase(defaultsTo.name);
149
+ defaultsTo.dependsOn = defaultsTo.dependsOn.map((dep) => ({
150
+ ...dep,
151
+ name: mainCase(dep.name),
152
+ }));
103
153
  }
104
154
  return { ...account, name: mainCase(account.name), defaultsTo };
105
155
  });
106
156
  this.args = args;
157
+ this.extraArgs = extraArgs;
107
158
  this.subInstructions = subInstructions;
108
159
  }
109
160
 
@@ -118,6 +169,7 @@ export class InstructionNode implements Visitable {
118
169
  docs: idl.docs ?? [],
119
170
  internal: false,
120
171
  bytesCreatedOnChain: null,
172
+ argDefaults: {},
121
173
  };
122
174
 
123
175
  const accounts = (idl.accounts ?? []).map(
@@ -135,7 +187,6 @@ export class InstructionNode implements Visitable {
135
187
  isOptional && useProgramIdForOptionalAccounts
136
188
  ? { kind: 'programId' }
137
189
  : null,
138
- pdaBumpArg: account.pdaBumpArg ?? null,
139
190
  };
140
191
  }
141
192
  );
@@ -164,7 +215,7 @@ export class InstructionNode implements Visitable {
164
215
  ]);
165
216
  }
166
217
 
167
- return new InstructionNode(metadata, accounts, args, []);
218
+ return new InstructionNode(metadata, accounts, args, null, []);
168
219
  }
169
220
 
170
221
  accept<T>(visitor: Visitor<T>): T {
@@ -186,20 +237,16 @@ export class InstructionNode implements Visitable {
186
237
  return this.metadata.docs;
187
238
  }
188
239
 
189
- get isLinked(): boolean {
240
+ get hasLinkedArgs(): boolean {
190
241
  return isTypeDefinedLinkNode(this.args);
191
242
  }
192
243
 
193
- get hasAccounts(): boolean {
194
- return this.accounts.length > 0;
195
- }
196
-
197
- get pdaAccounts(): InstructionNodeAccount[] {
198
- return this.accounts.filter((account) => account.pdaBumpArg !== null);
244
+ get hasLinkedExtraArgs(): boolean {
245
+ return isTypeDefinedLinkNode(this.extraArgs);
199
246
  }
200
247
 
201
- get hasPdaAccounts(): boolean {
202
- return this.pdaAccounts.length > 0;
248
+ get hasAccounts(): boolean {
249
+ return this.accounts.length > 0;
203
250
  }
204
251
 
205
252
  get hasData(): boolean {
@@ -215,12 +262,43 @@ export class InstructionNode implements Visitable {
215
262
  return nonOmittedFields.length > 0;
216
263
  }
217
264
 
218
- get hasRequiredArgs(): boolean {
219
- if (isTypeDefinedLinkNode(this.args)) return true;
220
- const requiredFields = this.args.fields.filter(
221
- (field) => field.metadata.defaultsTo === null
265
+ get hasExtraArgs(): boolean {
266
+ if (isTypeDefinedLinkNode(this.extraArgs)) return true;
267
+ const nonOmittedFields =
268
+ this.extraArgs?.fields.filter(
269
+ (field) => field.metadata.defaultsTo?.strategy !== 'omitted'
270
+ ) ?? [];
271
+ return nonOmittedFields.length > 0;
272
+ }
273
+
274
+ get hasAnyArgs(): boolean {
275
+ return this.hasArgs || this.hasExtraArgs;
276
+ }
277
+
278
+ get hasArgDefaults(): boolean {
279
+ return Object.keys(this.metadata.argDefaults).length > 0;
280
+ }
281
+
282
+ get hasArgResolvers(): boolean {
283
+ return Object.values(this.metadata.argDefaults).some(
284
+ ({ kind }) => kind === 'resolver'
285
+ );
286
+ }
287
+
288
+ get hasAccountResolvers(): boolean {
289
+ return this.accounts.some(
290
+ ({ defaultsTo }) => defaultsTo?.kind === 'resolver'
291
+ );
292
+ }
293
+
294
+ get hasByteResolver(): boolean {
295
+ return this.metadata.bytesCreatedOnChain?.kind === 'resolver';
296
+ }
297
+
298
+ get hasResolvers(): boolean {
299
+ return (
300
+ this.hasArgResolvers || this.hasAccountResolvers || this.hasByteResolver
222
301
  );
223
- return requiredFields.length > 0;
224
302
  }
225
303
  }
226
304
 
@@ -6,9 +6,10 @@ import { camelCase, pascalCase } from '../../utils';
6
6
  import {
7
7
  Visitor,
8
8
  BaseThrowVisitor,
9
- GetResolvedInstructionAccountsVisitor,
10
- ResolvedInstructionAccount,
9
+ GetResolvedInstructionInputsVisitor,
11
10
  Dependency,
11
+ ResolvedInstructionInput,
12
+ ResolvedInstructionAccount,
12
13
  } from '../../visitors';
13
14
  import { RenderMap } from '../RenderMap';
14
15
  import { resolveTemplate } from '../utils';
@@ -38,6 +39,9 @@ export type GetJavaScriptRenderMapOptions = {
38
39
  setImportStrategy: (
39
40
  importStrategy: 'all' | 'looseOnly' | 'strictOnly'
40
41
  ) => void;
42
+ setDefinedName: (
43
+ definedName: { strict: string; loose: string } | null
44
+ ) => void;
41
45
  };
42
46
  };
43
47
 
@@ -46,9 +50,7 @@ export class GetJavaScriptRenderMapVisitor extends BaseThrowVisitor<RenderMap> {
46
50
 
47
51
  private program: nodes.ProgramNode | null = null;
48
52
 
49
- private resolvedInstructionAccountVisitor: Visitor<
50
- ResolvedInstructionAccount[]
51
- >;
53
+ private resolvedInstructionInputVisitor: Visitor<ResolvedInstructionInput[]>;
52
54
 
53
55
  constructor(options: GetJavaScriptRenderMapOptions = {}) {
54
56
  super();
@@ -72,8 +74,8 @@ export class GetJavaScriptRenderMapVisitor extends BaseThrowVisitor<RenderMap> {
72
74
  typeManifestVisitor:
73
75
  options.typeManifestVisitor ?? new GetJavaScriptTypeManifestVisitor(),
74
76
  };
75
- this.resolvedInstructionAccountVisitor =
76
- new GetResolvedInstructionAccountsVisitor();
77
+ this.resolvedInstructionInputVisitor =
78
+ new GetResolvedInstructionInputsVisitor();
77
79
  }
78
80
 
79
81
  visitRoot(root: nodes.RootNode): RenderMap {
@@ -163,7 +165,13 @@ export class GetJavaScriptRenderMapVisitor extends BaseThrowVisitor<RenderMap> {
163
165
  `programs/${camelCase(name)}.ts`,
164
166
  this.render('programsPage.njk', {
165
167
  imports: new JavaScriptImportMap()
166
- .add('core', ['Program', 'publicKey'])
168
+ .add('core', [
169
+ 'ClusterFilter',
170
+ 'Context',
171
+ 'Program',
172
+ 'publicKey',
173
+ 'PublicKey',
174
+ ])
167
175
  .add('errors', [
168
176
  `get${pascalCaseName}ErrorFromCode`,
169
177
  `get${pascalCaseName}ErrorFromName`,
@@ -299,28 +307,42 @@ export class GetJavaScriptRenderMapVisitor extends BaseThrowVisitor<RenderMap> {
299
307
  'transactionBuilder',
300
308
  ]);
301
309
 
302
- // Accounts.
303
- const accounts = instruction
304
- .accept(this.resolvedInstructionAccountVisitor)
305
- .map((account) => {
306
- const hasDefaultValue = !!account.defaultsTo;
307
- if (account.defaultsTo?.kind === 'pda') {
308
- const { seeds } = account.defaultsTo;
310
+ // Resolved inputs.
311
+ const resolvedInputs = instruction
312
+ .accept(this.resolvedInstructionInputVisitor)
313
+ .map((input: ResolvedInstructionInput) => {
314
+ if (input.kind === 'account' && input.defaultsTo?.kind === 'pda') {
315
+ const { seeds } = input.defaultsTo;
309
316
  Object.keys(seeds).forEach((seed: string) => {
310
317
  const seedValue = seeds[seed];
311
318
  if (seedValue.kind !== 'value') return;
312
- const seedManifest = renderJavaScriptValueNode(seedValue.value);
313
- (seedValue as any).render = seedManifest.render;
314
- imports.mergeWith(seedManifest.imports);
319
+ const valueManifest = renderJavaScriptValueNode(seedValue.value);
320
+ (seedValue as any).render = valueManifest.render;
321
+ imports.mergeWith(valueManifest.imports);
315
322
  });
316
323
  }
317
- return {
318
- ...account,
319
- type: this.getInstructionAccountType(account),
320
- optionalSign: hasDefaultValue || account.isOptional ? '?' : '',
321
- hasDefaultValue,
322
- };
324
+ if (input.kind === 'arg' && input.defaultsTo.kind === 'value') {
325
+ const { defaultsTo } = input;
326
+ const valueManifest = renderJavaScriptValueNode(defaultsTo.value);
327
+ (defaultsTo as any).render = valueManifest.render;
328
+ imports.mergeWith(valueManifest.imports);
329
+ }
330
+ return input;
323
331
  });
332
+
333
+ // Accounts.
334
+ const accounts = instruction.accounts.map((account) => {
335
+ const hasDefaultValue = !!account.defaultsTo;
336
+ const resolvedAccount = resolvedInputs.find(
337
+ (input) => input.kind === 'account' && input.name === account.name
338
+ ) as ResolvedInstructionAccount;
339
+ return {
340
+ ...resolvedAccount,
341
+ type: this.getInstructionAccountType(resolvedAccount),
342
+ optionalSign: hasDefaultValue || account.isOptional ? '?' : '',
343
+ hasDefaultValue,
344
+ };
345
+ });
324
346
  imports.mergeWith(this.getInstructionAccountImports(accounts));
325
347
  if (accounts.length > 0) {
326
348
  imports
@@ -328,16 +350,41 @@ export class GetJavaScriptRenderMapVisitor extends BaseThrowVisitor<RenderMap> {
328
350
  .addAlias('core', 'checkForIsWritableOverride', 'isWritable');
329
351
  }
330
352
 
331
- // Arguments.
332
- const typeManifest = instruction.accept(this.typeManifestVisitor);
333
- imports.mergeWith(typeManifest.imports);
353
+ // Args.
354
+ const argManifest = instruction.accept(this.typeManifestVisitor);
355
+ imports.mergeWith(argManifest.imports);
334
356
  if (!nodes.isTypeDefinedLinkNode(instruction.args) && instruction.hasData) {
335
357
  imports.add('core', ['Serializer']);
336
358
  }
337
359
 
360
+ // Extra args.
361
+ let extraArgManifest: JavaScriptTypeManifest | null = null;
362
+ if (instruction.extraArgs) {
363
+ this.typeManifestVisitor.setDefinedName({
364
+ strict: `${pascalCase(instruction.name)}InstructionExtra`,
365
+ loose: `${pascalCase(instruction.name)}InstructionExtraArgs`,
366
+ });
367
+ if (nodes.isTypeDefinedLinkNode(instruction.extraArgs)) {
368
+ this.typeManifestVisitor.setImportStrategy('looseOnly');
369
+ }
370
+ extraArgManifest = instruction.extraArgs.accept(this.typeManifestVisitor);
371
+ this.typeManifestVisitor.setDefinedName(null);
372
+ this.typeManifestVisitor.setImportStrategy('all');
373
+ imports.mergeWith(extraArgManifest.imports);
374
+ }
375
+
376
+ // Arg defaults.
377
+ const argDefaultKeys = Object.keys(instruction.metadata.argDefaults);
378
+ const argDefaults = Object.values(instruction.metadata.argDefaults);
379
+ argDefaults.forEach((argDefault) => {
380
+ if (argDefault.kind === 'resolver') {
381
+ imports.add(argDefault.dependency, camelCase(argDefault.name));
382
+ }
383
+ });
384
+
338
385
  // Bytes created on chain.
339
386
  const bytes = instruction.metadata.bytesCreatedOnChain;
340
- if (bytes && bytes.includeHeader) {
387
+ if (bytes && 'includeHeader' in bytes && bytes.includeHeader) {
341
388
  imports.add('core', 'ACCOUNT_HEADER_SIZE');
342
389
  }
343
390
  if (bytes?.kind === 'account') {
@@ -347,6 +394,8 @@ export class GetJavaScriptRenderMapVisitor extends BaseThrowVisitor<RenderMap> {
347
394
  ? 'generatedAccounts'
348
395
  : bytes.dependency;
349
396
  imports.add(dependency, `get${accountName}Size`);
397
+ } else if (bytes?.kind === 'resolver') {
398
+ imports.add(bytes.dependency, camelCase(bytes.name));
350
399
  }
351
400
 
352
401
  // Remove imports from the same module.
@@ -358,7 +407,10 @@ export class GetJavaScriptRenderMapVisitor extends BaseThrowVisitor<RenderMap> {
358
407
 
359
408
  // canMergeAccountsAndArgs
360
409
  let canMergeAccountsAndArgs = false;
361
- if (!nodes.isTypeDefinedLinkNode(instruction.args)) {
410
+ if (
411
+ !nodes.isTypeDefinedLinkNode(instruction.args) &&
412
+ !nodes.isTypeDefinedLinkNode(instruction.extraArgs)
413
+ ) {
362
414
  const accountsAndArgsConflicts =
363
415
  this.getMergeConflictsForInstructionAccountsAndArgs(instruction);
364
416
  if (accountsAndArgsConflicts.length > 0) {
@@ -374,17 +426,25 @@ export class GetJavaScriptRenderMapVisitor extends BaseThrowVisitor<RenderMap> {
374
426
  canMergeAccountsAndArgs = accountsAndArgsConflicts.length === 0;
375
427
  }
376
428
 
429
+ const hasAccountDefaultKinds = (
430
+ kinds: Array<nodes.InstructionNodeAccountDefaults['kind']>
431
+ ) =>
432
+ accounts.some((a) => a.defaultsTo && kinds.includes(a.defaultsTo.kind));
433
+
377
434
  return new RenderMap().add(
378
435
  `instructions/${camelCase(instruction.name)}.ts`,
379
436
  this.render('instructionsPage.njk', {
380
437
  instruction,
381
438
  imports: imports.toString(this.options.dependencyMap),
382
439
  program: this.program,
440
+ resolvedInputs,
383
441
  accounts,
384
- needsEddsa: accounts.some((a) => a.defaultsTo?.kind === 'pda'),
385
- needsIdentity: accounts.some((a) => a.defaultsTo?.kind === 'identity'),
386
- needsPayer: accounts.some((a) => a.defaultsTo?.kind === 'payer'),
387
- typeManifest,
442
+ needsEddsa: hasAccountDefaultKinds(['pda', 'resolver']),
443
+ needsIdentity: hasAccountDefaultKinds(['identity', 'resolver']),
444
+ needsPayer: hasAccountDefaultKinds(['payer', 'resolver']),
445
+ argDefaultKeys,
446
+ argManifest,
447
+ extraArgManifest,
388
448
  canMergeAccountsAndArgs,
389
449
  })
390
450
  );
@@ -417,7 +477,7 @@ export class GetJavaScriptRenderMapVisitor extends BaseThrowVisitor<RenderMap> {
417
477
  protected getInstructionAccountType(
418
478
  account: ResolvedInstructionAccount
419
479
  ): string {
420
- if (account.pdaBumpArg) return 'Pda';
480
+ if (account.isPda && account.isSigner === false) return 'Pda';
421
481
  if (account.isSigner === 'either') return 'PublicKey | Signer';
422
482
  return account.isSigner ? 'Signer' : 'PublicKey';
423
483
  }
@@ -427,13 +487,12 @@ export class GetJavaScriptRenderMapVisitor extends BaseThrowVisitor<RenderMap> {
427
487
  ): JavaScriptImportMap {
428
488
  const imports = new JavaScriptImportMap();
429
489
  accounts.forEach((account) => {
430
- if (account.pdaBumpArg) {
490
+ if (account.isPda && account.isSigner === false) {
431
491
  imports.add('core', 'Pda');
432
492
  }
433
493
  if (account.defaultsTo?.kind === 'publicKey') {
434
494
  imports.add('core', 'publicKey');
435
- }
436
- if (account.defaultsTo?.kind === 'pda') {
495
+ } else if (account.defaultsTo?.kind === 'pda') {
437
496
  const pdaAccount = pascalCase(account.defaultsTo.pdaAccount);
438
497
  const dependency =
439
498
  account.defaultsTo.dependency === 'generated'
@@ -445,6 +504,11 @@ export class GetJavaScriptRenderMapVisitor extends BaseThrowVisitor<RenderMap> {
445
504
  imports.add('core', 'publicKey');
446
505
  }
447
506
  });
507
+ } else if (account.defaultsTo?.kind === 'resolver') {
508
+ imports.add(
509
+ account.defaultsTo.dependency,
510
+ camelCase(account.defaultsTo.name)
511
+ );
448
512
  }
449
513
  if (account.resolvedIsSigner === 'either') {
450
514
  imports.add('core', ['PublicKey', 'publicKey', 'Signer', 'isSigner']);
@@ -461,9 +525,14 @@ export class GetJavaScriptRenderMapVisitor extends BaseThrowVisitor<RenderMap> {
461
525
  instruction: nodes.InstructionNode
462
526
  ): string[] {
463
527
  nodes.assertTypeStructNode(instruction.args);
528
+ let extraArgsFields: nodes.TypeStructFieldNode[] = [];
529
+ if (nodes.isTypeStructNode(instruction.extraArgs)) {
530
+ extraArgsFields = instruction.extraArgs.fields;
531
+ }
464
532
  const allNames = [
465
533
  ...instruction.accounts.map((account) => account.name),
466
534
  ...instruction.args.fields.map((field) => field.name),
535
+ ...extraArgsFields.map((field) => field.name),
467
536
  ];
468
537
  const duplicates = allNames.filter((e, i, a) => a.indexOf(e) !== i);
469
538
  return [...new Set(duplicates)];
@@ -31,6 +31,12 @@ export class GetJavaScriptTypeManifestVisitor
31
31
  this.importStrategy = strategy;
32
32
  }
33
33
 
34
+ setDefinedName(
35
+ definedName: GetJavaScriptTypeManifestVisitor['definedName']
36
+ ): void {
37
+ this.definedName = definedName;
38
+ }
39
+
34
40
  visitRoot(): JavaScriptTypeManifest {
35
41
  throw new Error(
36
42
  'Cannot get type manifest for root node. Please select a child node.'
@@ -86,6 +86,8 @@ export class GetJavaScriptValidatorBagVisitor extends GetDefaultValidatorBagVisi
86
86
  [`${pascalCaseName}InstructionData`]: 'type',
87
87
  [`${pascalCaseName}InstructionDataArgs`]: 'type',
88
88
  [`get${pascalCaseName}InstructionDataSerializer`]: 'function',
89
+ [`${pascalCaseName}InstructionExtraArgs`]: 'type',
90
+ [`${pascalCaseName}InstructionArgs`]: 'type',
89
91
  }),
90
92
  ]);
91
93
  }