@better-sol/cli 0.1.0-alpha.11 → 0.1.0-alpha.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -388,13 +388,11 @@ function collectAccounts(source, program, rawStructZCs) {
388
388
  const firstArg = call.arguments[0];
389
389
  if (firstArg === void 0 || !isObjectExpression(firstArg)) continue;
390
390
  const fields = parseFields(source, firstArg);
391
- const chainText = nodeTextOf(source, decl.init);
392
- if (chainText.includes(".pda(")) throw new Error(".pda() was renamed to .derive(). Use .derive((seed) => ['literal', seed.fieldName]).");
393
- if (chainText.includes(".seeds(")) throw new Error(".seeds() was removed. Use .derive((seed) => ['literal', seed.fieldName]).");
394
- const zeroCopy = chainText.includes(".zeroCopy");
391
+ const zeroCopy = hasChainMethod(source, decl.init, "zeroCopy");
395
392
  if (zeroCopy) validateZeroCopyFields(name, fields, rawStructZCs);
396
- const seeds = parseSeeds(chainText);
397
- const hasOneFields = parseHasOneFields(chainText);
393
+ const deriveCall = findChainCall(source, decl.init, "derive");
394
+ const seeds = deriveCall !== void 0 ? parseSeedsFromAst(source, deriveCall) : [];
395
+ const hasOneFields = parseHasOneFieldsFromAst(source, decl.init);
398
396
  accounts.push({
399
397
  name,
400
398
  fields,
@@ -578,6 +576,17 @@ function resolveConstraint(source, prop, accountName, rawAccounts) {
578
576
  };
579
577
  }
580
578
  case "remaining": {
579
+ const argNode = init.arguments[0];
580
+ if (argNode !== void 0 && isIdentifier(argNode)) {
581
+ if (argNode.name === "tokenAccount" || argNode.name.includes("TokenAccount") || argNode.name.includes("tokenAccount")) return {
582
+ kind: "remaining",
583
+ itemType: "tokenAccount"
584
+ };
585
+ if (argNode.name === "signer" || argNode.name.includes("Signer")) return {
586
+ kind: "remaining",
587
+ itemType: "signer"
588
+ };
589
+ }
581
590
  const argText = getCallArgText(source, init, 0) ?? "";
582
591
  if (argText.includes("tokenAccount")) return {
583
592
  kind: "remaining",
@@ -704,50 +713,73 @@ function tryResolvePrimitive(name) {
704
713
  "bytes"
705
714
  ].includes(name) ? name : void 0;
706
715
  }
707
- function parseSeeds(chainText) {
708
- const args = extractPdaArgs(chainText);
709
- if (args === void 0) return [];
716
+ function hasChainMethod(source, node, methodName) {
717
+ return findChainCall(source, node, methodName) !== void 0;
718
+ }
719
+ function findChainCall(source, node, methodName) {
720
+ let current = node;
721
+ while (current !== void 0) {
722
+ if (!isCallExpression(current)) break;
723
+ if (isMemberExpression(current.callee)) {
724
+ if (getMemberPropertyName(source, current.callee) === methodName) return current;
725
+ current = current.callee.object;
726
+ } else break;
727
+ }
728
+ }
729
+ function parseSeedsFromAst(source, deriveCall) {
730
+ const firstArg = deriveCall.arguments[0];
731
+ if (firstArg === void 0 || !isArrowFunctionExpression(firstArg)) return [];
732
+ const body = unwrapParenthesized(firstArg.body);
733
+ if (!isArrayExpression(body)) return [];
710
734
  const seeds = [];
711
- const regex = /\b[A-Za-z_$][\w$]*\.([A-Za-z_$][\w$]*)|'([^']*)'|"([^"]*)"/g;
712
- let match;
713
- while ((match = regex.exec(args)) !== null) {
714
- const field = match[1];
715
- const singleQuotedLiteral = match[2];
716
- const doubleQuotedLiteral = match[3];
717
- if (field !== void 0) seeds.push({
718
- kind: "field",
719
- fieldName: field
720
- });
721
- else if (singleQuotedLiteral !== void 0 && singleQuotedLiteral !== "") seeds.push(parseLiteralSeed(singleQuotedLiteral));
722
- else if (doubleQuotedLiteral !== void 0 && doubleQuotedLiteral !== "") seeds.push(parseLiteralSeed(doubleQuotedLiteral));
735
+ for (const element of body.elements) {
736
+ if (element === void 0 || element === null || isSpreadElement(element)) continue;
737
+ const seed = parseSingleSeed(source, element);
738
+ if (seed !== void 0) seeds.push(seed);
723
739
  }
724
740
  return seeds;
725
741
  }
742
+ function parseSingleSeed(source, node) {
743
+ if (isStringLiteral(node)) return parseLiteralSeed(node.value);
744
+ if (isTemplateLiteral(node) && node.quasis.length === 1) {
745
+ const quasi = node.quasis[0];
746
+ if (quasi !== void 0) return parseLiteralSeed(quasi.value.cooked ?? quasi.value.raw);
747
+ }
748
+ if (isMemberExpression(node)) {
749
+ const property = getMemberPropertyName(source, node);
750
+ if (property !== void 0) return {
751
+ kind: "field",
752
+ fieldName: property
753
+ };
754
+ }
755
+ if (isCallExpression(node) && isMemberExpression(node.callee)) {
756
+ const property = getMemberPropertyName(source, node.callee);
757
+ if (property !== void 0) return {
758
+ kind: "field",
759
+ fieldName: property
760
+ };
761
+ }
762
+ }
726
763
  function parseLiteralSeed(value) {
727
- if (/^\{[A-Za-z_$][\w$]*\}$/.test(value)) throw new Error(`Dynamic PDA seed template '${value}' is not supported. Store the value as an account field and reference it with seed.${value.slice(1, -1)}.`);
728
764
  return {
729
765
  kind: "literal",
730
766
  value
731
767
  };
732
768
  }
733
- function parseHasOneFields(chainText) {
769
+ function parseHasOneFieldsFromAst(source, node) {
734
770
  const fields = [];
735
- const regex = /\.hasOne\(["']([^"']+)["']\)/g;
736
- let match;
737
- while ((match = regex.exec(chainText)) !== null) fields.push(match[1]);
738
- return fields;
739
- }
740
- function extractPdaArgs(chainText) {
741
- const start = chainText.indexOf(".derive(");
742
- if (start === -1) return void 0;
743
- const argsStart = start + 8;
744
- let depth = 1;
745
- for (let index = argsStart; index < chainText.length; index += 1) {
746
- const char = chainText[index];
747
- if (char === "(") depth += 1;
748
- else if (char === ")") depth -= 1;
749
- if (depth === 0) return chainText.slice(argsStart, index);
771
+ let current = node;
772
+ while (current !== void 0) {
773
+ if (!isCallExpression(current)) break;
774
+ if (isMemberExpression(current.callee)) {
775
+ if (getMemberPropertyName(source, current.callee) === "hasOne") {
776
+ const arg = current.arguments[0];
777
+ if (isStringLiteral(arg)) fields.push(arg.value);
778
+ }
779
+ current = current.callee.object;
780
+ } else break;
750
781
  }
782
+ return fields;
751
783
  }
752
784
  function validateZeroCopyFields(accountName, fields, structs) {
753
785
  for (const field of fields) try {
@@ -69328,7 +69360,7 @@ async function gitCommit() {
69328
69360
  //#endregion
69329
69361
  //#region src/index.ts
69330
69362
  const cli = new Command();
69331
- cli.name("better-sol").description("Write Solana programs in TypeScript. Run with npx @better-sol/cli@alpha").version("0.1.0-alpha.11");
69363
+ cli.name("better-sol").description("Write Solana programs in TypeScript. Run with npx @better-sol/cli@alpha").version("0.1.0-alpha.12");
69332
69364
  cli.command("init").description("Initialize a better-sol project").option("--force", "overwrite existing files", false).option("--skip-install", "skip installing dependencies", false).action((options) => run(() => init(options)));
69333
69365
  cli.command("create").description("Create a new better-sol program").argument("[name]", "program name").option("--dir <dir>", "program directory", "programs").option("--force", "overwrite existing files", false).action((name, options) => run(() => create(name, options)));
69334
69366
  cli.command("login").description("Save your compiler API key").argument("[apiKey]", "compiler API key").action((apiKey) => run(() => login(apiKey)));