@better-sol/cli 0.1.0-alpha.11 → 0.1.0-alpha.13
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 +224 -70
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,11 +3,11 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
import { cancel, confirm, intro, isCancel, log, outro, select, spinner, text } from "@clack/prompts";
|
|
4
4
|
import { Command } from "commander";
|
|
5
5
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
6
|
-
import path, { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
6
|
+
import path, { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
7
7
|
import { homedir, tmpdir } from "node:os";
|
|
8
8
|
import { execFile, execSync } from "node:child_process";
|
|
9
9
|
import { generateKeyPairSigner, getAddressDecoder } from "@solana/kit";
|
|
10
|
-
import { access, mkdir, mkdtemp, opendir, readFile, rm, writeFile } from "node:fs/promises";
|
|
10
|
+
import { access, mkdir, mkdtemp, opendir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
11
11
|
import { parseSync } from "oxc-parser";
|
|
12
12
|
import { promisify } from "node:util";
|
|
13
13
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
@@ -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
|
|
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
|
|
397
|
-
const
|
|
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
|
|
708
|
-
|
|
709
|
-
|
|
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
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
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
|
|
769
|
+
function parseHasOneFieldsFromAst(source, node) {
|
|
734
770
|
const fields = [];
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
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 {
|
|
@@ -3500,12 +3532,21 @@ function flattenAccountItems(items) {
|
|
|
3500
3532
|
return result;
|
|
3501
3533
|
}
|
|
3502
3534
|
function idlTypeToCode(type) {
|
|
3503
|
-
if (typeof type === "string")
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
if ("
|
|
3508
|
-
|
|
3535
|
+
if (typeof type === "string") {
|
|
3536
|
+
if (type === "publicKey") return "bs.pubkey()";
|
|
3537
|
+
return `bs.${type}()`;
|
|
3538
|
+
}
|
|
3539
|
+
if (typeof type !== "object" || type === null) return "bs.pubkey()";
|
|
3540
|
+
const record = type;
|
|
3541
|
+
const option = record.option;
|
|
3542
|
+
if (option !== void 0) return `bs.optional(${idlTypeToCode(option)})`;
|
|
3543
|
+
const coption = record.coption;
|
|
3544
|
+
if (coption !== void 0) return `bs.optional(${idlTypeToCode(coption)})`;
|
|
3545
|
+
const vec = record.vec;
|
|
3546
|
+
if (vec !== void 0) return `bs.vector(${idlTypeToCode(vec)})`;
|
|
3547
|
+
const array = record.array;
|
|
3548
|
+
if (Array.isArray(array) && array.length === 2) return `bs.array(${idlTypeToCode(array[0])}, ${array[1]})`;
|
|
3549
|
+
if (record.defined !== void 0) return "bs.pubkey()";
|
|
3509
3550
|
return "bs.pubkey()";
|
|
3510
3551
|
}
|
|
3511
3552
|
function escapeString(str) {
|
|
@@ -3521,18 +3562,35 @@ function getStructFields(typeDef) {
|
|
|
3521
3562
|
if (!Array.isArray(fields)) return [];
|
|
3522
3563
|
return fields;
|
|
3523
3564
|
}
|
|
3565
|
+
function getStructFieldsFromAccount(account) {
|
|
3566
|
+
if (typeof account !== "object" || account === null) return [];
|
|
3567
|
+
const accountType = account.type;
|
|
3568
|
+
if (typeof accountType !== "object" || accountType === null) return [];
|
|
3569
|
+
const typeRecord = accountType;
|
|
3570
|
+
if (typeRecord.kind !== "struct") return [];
|
|
3571
|
+
const fields = typeRecord.fields;
|
|
3572
|
+
if (!Array.isArray(fields)) return [];
|
|
3573
|
+
return fields;
|
|
3574
|
+
}
|
|
3575
|
+
function getIdlName$1(idl) {
|
|
3576
|
+
if (typeof idl.metadata?.name === "string") return idl.metadata.name;
|
|
3577
|
+
const record = idl;
|
|
3578
|
+
return typeof record.name === "string" ? record.name : void 0;
|
|
3579
|
+
}
|
|
3524
3580
|
function generateIdlProgram(idl, sourceLabel) {
|
|
3525
3581
|
const w = new CodeWriter();
|
|
3526
|
-
const programName = idl
|
|
3582
|
+
const programName = toCamel(getIdlName$1(idl) ?? "unknown");
|
|
3527
3583
|
const programAddress = idl.address ?? "";
|
|
3528
3584
|
const typesByName = /* @__PURE__ */ new Map();
|
|
3529
3585
|
for (const t of idl.types ?? []) typesByName.set(t.name, t);
|
|
3530
3586
|
const accountDefs = idl.accounts ?? [];
|
|
3531
3587
|
const resolvedAccounts = /* @__PURE__ */ new Map();
|
|
3532
3588
|
for (const acc of accountDefs) {
|
|
3533
|
-
const
|
|
3589
|
+
const fromTypes = getStructFields(typesByName.get(acc.name));
|
|
3590
|
+
const fromAccount = getStructFieldsFromAccount(acc);
|
|
3591
|
+
const fields = fromTypes.length > 0 ? fromTypes : fromAccount;
|
|
3534
3592
|
resolvedAccounts.set(acc.name, {
|
|
3535
|
-
|
|
3593
|
+
exportName: toPascal(acc.name),
|
|
3536
3594
|
fields
|
|
3537
3595
|
});
|
|
3538
3596
|
}
|
|
@@ -3541,11 +3599,11 @@ function generateIdlProgram(idl, sourceLabel) {
|
|
|
3541
3599
|
w.line(`// Generated by better-sol from ${sourceLabel}. Do not edit.`);
|
|
3542
3600
|
w.line(`import { bs } from "better-sol/program"`);
|
|
3543
3601
|
w.blank();
|
|
3544
|
-
for (const [
|
|
3602
|
+
for (const [, { exportName, fields }] of resolvedAccounts) {
|
|
3545
3603
|
if (fields.length === 0) continue;
|
|
3546
|
-
w.line(`const ${
|
|
3604
|
+
w.line(`const ${exportName} = bs.account({`);
|
|
3547
3605
|
w.indent(1);
|
|
3548
|
-
for (const field of fields) w.line(`${field.name}: ${idlTypeToCode(field.type)},`);
|
|
3606
|
+
for (const field of fields) w.line(`${toCamel(field.name)}: ${idlTypeToCode(field.type)},`);
|
|
3549
3607
|
w.indent(0);
|
|
3550
3608
|
w.line("})");
|
|
3551
3609
|
w.blank();
|
|
@@ -3558,10 +3616,9 @@ function generateIdlProgram(idl, sourceLabel) {
|
|
|
3558
3616
|
w.line(`address: "${escapeString(programAddress)}",`);
|
|
3559
3617
|
if (resolvedAccounts.size > 0) {
|
|
3560
3618
|
w.line(`accounts: {`);
|
|
3561
|
-
for (const
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
w.line(` ${name},`);
|
|
3619
|
+
for (const [, { exportName, fields }] of resolvedAccounts) {
|
|
3620
|
+
if (fields.length === 0) continue;
|
|
3621
|
+
w.line(` ${exportName},`);
|
|
3565
3622
|
}
|
|
3566
3623
|
w.line(`},`);
|
|
3567
3624
|
}
|
|
@@ -3569,7 +3626,7 @@ function generateIdlProgram(idl, sourceLabel) {
|
|
|
3569
3626
|
w.line(`errors: {`);
|
|
3570
3627
|
for (const err of errorEntries) {
|
|
3571
3628
|
const msg = err.msg ?? err.name;
|
|
3572
|
-
w.line(` ${err.name}: "${escapeString(msg)}",`);
|
|
3629
|
+
w.line(` ${toPascal(err.name)}: "${escapeString(msg)}",`);
|
|
3573
3630
|
}
|
|
3574
3631
|
w.line(`},`);
|
|
3575
3632
|
}
|
|
@@ -3577,8 +3634,8 @@ function generateIdlProgram(idl, sourceLabel) {
|
|
|
3577
3634
|
w.line(`events: {`);
|
|
3578
3635
|
for (const ev of eventEntries) {
|
|
3579
3636
|
const fields = getStructFields(typesByName.get(ev.name));
|
|
3580
|
-
w.line(` ${ev.name}: {`);
|
|
3581
|
-
for (const f of fields) w.line(` ${f.name}: ${idlTypeToCode(f.type)},`);
|
|
3637
|
+
w.line(` ${toPascal(ev.name)}: {`);
|
|
3638
|
+
for (const f of fields) w.line(` ${toCamel(f.name)}: ${idlTypeToCode(f.type)},`);
|
|
3582
3639
|
w.line(` },`);
|
|
3583
3640
|
}
|
|
3584
3641
|
w.line(`},`);
|
|
@@ -3587,21 +3644,22 @@ function generateIdlProgram(idl, sourceLabel) {
|
|
|
3587
3644
|
w.line(`}, ix => ({`);
|
|
3588
3645
|
for (const instr of idl.instructions) {
|
|
3589
3646
|
const flatAccounts = flattenAccountItems(instr.accounts);
|
|
3647
|
+
const ixName = toCamel(instr.name);
|
|
3590
3648
|
w.blank();
|
|
3591
|
-
w.line(`${
|
|
3649
|
+
w.line(`${ixName}: ix({`);
|
|
3592
3650
|
if (flatAccounts.length > 0) {
|
|
3593
3651
|
w.line(` accounts: {`);
|
|
3594
3652
|
for (const acc of flatAccounts) {
|
|
3595
3653
|
if (acc.optional === true) continue;
|
|
3596
3654
|
const constraint = accountToConstraint(acc, resolvedAccounts);
|
|
3597
|
-
w.line(` ${acc.name}: ${constraint},`);
|
|
3655
|
+
w.line(` ${toCamel(acc.name)}: ${constraint},`);
|
|
3598
3656
|
}
|
|
3599
3657
|
w.line(` },`);
|
|
3600
3658
|
}
|
|
3601
3659
|
const args = instr.args ?? [];
|
|
3602
3660
|
if (args.length > 0) {
|
|
3603
3661
|
w.line(` args: {`);
|
|
3604
|
-
for (const arg of args) w.line(` ${arg.name}: ${idlTypeToCode(arg.type)},`);
|
|
3662
|
+
for (const arg of args) w.line(` ${toCamel(arg.name)}: ${idlTypeToCode(arg.type)},`);
|
|
3605
3663
|
w.line(` },`);
|
|
3606
3664
|
}
|
|
3607
3665
|
if (instr.returns !== void 0) w.line(` returns: ${idlTypeToCode(instr.returns)},`);
|
|
@@ -3617,15 +3675,22 @@ function generateIdlProgram(idl, sourceLabel) {
|
|
|
3617
3675
|
}
|
|
3618
3676
|
function accountToConstraint(acc, resolvedAccounts) {
|
|
3619
3677
|
if (acc.signer === true) return "bs.signer()";
|
|
3620
|
-
const
|
|
3678
|
+
const resolved = resolveAccountDefinition(acc.name, resolvedAccounts);
|
|
3679
|
+
const accountRef = resolved !== void 0 && resolved.fields.length > 0 ? resolved.exportName : "bs.account({})";
|
|
3621
3680
|
if (acc.writable === true) return `bs.mut(${accountRef})`;
|
|
3622
3681
|
return accountRef;
|
|
3623
3682
|
}
|
|
3683
|
+
function resolveAccountDefinition(accountName, resolvedAccounts) {
|
|
3684
|
+
const exact = resolvedAccounts.get(accountName);
|
|
3685
|
+
if (exact !== void 0) return exact;
|
|
3686
|
+
const pascalName = toPascal(accountName);
|
|
3687
|
+
for (const [idlName, account] of resolvedAccounts) if (idlName === pascalName || account.exportName === pascalName) return account;
|
|
3688
|
+
}
|
|
3624
3689
|
function runParams(accounts, args) {
|
|
3625
3690
|
const parts = [];
|
|
3626
|
-
const accountNames = accounts.filter((a) => a.optional !== true).map((a) => a.name);
|
|
3691
|
+
const accountNames = accounts.filter((a) => a.optional !== true).map((a) => toCamel(a.name));
|
|
3627
3692
|
if (accountNames.length > 0) parts.push(`{ ${accountNames.join(", ")} }`);
|
|
3628
|
-
const argNames = args.map((a) => a.name);
|
|
3693
|
+
const argNames = args.map((a) => toCamel(a.name));
|
|
3629
3694
|
if (argNames.length > 0) parts.push(`{ ${argNames.join(", ")} }`);
|
|
3630
3695
|
parts.push("ctx");
|
|
3631
3696
|
return parts.join(", ");
|
|
@@ -69213,7 +69278,7 @@ async function generateIdl(input, options) {
|
|
|
69213
69278
|
sourceLabel = basename(idlPath);
|
|
69214
69279
|
s.stop("IDL loaded");
|
|
69215
69280
|
}
|
|
69216
|
-
const programName = options.name ?? idl
|
|
69281
|
+
const programName = toCamel(options.name ?? getIdlName(idl) ?? "program");
|
|
69217
69282
|
const outPath = cwdPath(options.out ?? `generated/${programName}.ts`);
|
|
69218
69283
|
s.message("Generating program definition");
|
|
69219
69284
|
const code = generateIdlProgram(idl, sourceLabel);
|
|
@@ -69221,12 +69286,101 @@ async function generateIdl(input, options) {
|
|
|
69221
69286
|
await writeFile(outPath, code, "utf-8");
|
|
69222
69287
|
s.stop("Generated");
|
|
69223
69288
|
log.info(`Wrote ${resolve(outPath)}`);
|
|
69224
|
-
|
|
69225
|
-
log.step(`Import it in your app:\n\n import { ${programName} } from "./${importPath}"\n\nThen register it with the client:\n\n const sol = await betterSol({ programs: { ${programName} } })`);
|
|
69289
|
+
log.step(await buildImportGuide(outPath, programName));
|
|
69226
69290
|
outro("Done");
|
|
69227
69291
|
}
|
|
69292
|
+
const IGNORED_DIRECTORIES = new Set([
|
|
69293
|
+
".better-sol",
|
|
69294
|
+
".git",
|
|
69295
|
+
".next",
|
|
69296
|
+
"dist",
|
|
69297
|
+
"build",
|
|
69298
|
+
"node_modules"
|
|
69299
|
+
]);
|
|
69300
|
+
async function buildImportGuide(outPath, programName) {
|
|
69301
|
+
const usage = await findBetterSolUsage(process.cwd());
|
|
69302
|
+
if (usage !== void 0) return `Import it in ${relativePath(process.cwd(), usage.filePath)}:\n\n import { ${programName} } from "${moduleSpecifier(dirname(usage.filePath), outPath)}"\n\n${usage.hasProgramsObject ? `Add it to the existing programs object:\n\n programs: { ..., ${programName} }` : `Register it with the client:\n\n const sol = await betterSol({ programs: { ${programName} } })`}`;
|
|
69303
|
+
return `Import it in your app:\n\n import { ${programName} } from "${moduleSpecifier(process.cwd(), outPath)}"\n\nThen register it with the client:\n\n const sol = await betterSol({ programs: { ${programName} } })`;
|
|
69304
|
+
}
|
|
69305
|
+
async function findBetterSolUsage(root) {
|
|
69306
|
+
const files = await collectTypeScriptFiles(root);
|
|
69307
|
+
let fallback;
|
|
69308
|
+
for (const filePath of files) {
|
|
69309
|
+
const usage = parseBetterSolUsage(await readFile(filePath, "utf-8"), filePath);
|
|
69310
|
+
if (usage === void 0) continue;
|
|
69311
|
+
if (usage.hasProgramsObject) return usage;
|
|
69312
|
+
fallback ??= usage;
|
|
69313
|
+
}
|
|
69314
|
+
return fallback;
|
|
69315
|
+
}
|
|
69316
|
+
async function collectTypeScriptFiles(root) {
|
|
69317
|
+
const results = [];
|
|
69318
|
+
await collectTypeScriptFilesInto(root, results);
|
|
69319
|
+
return results.sort();
|
|
69320
|
+
}
|
|
69321
|
+
async function collectTypeScriptFilesInto(directory, results) {
|
|
69322
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
69323
|
+
for (const entry of entries) {
|
|
69324
|
+
const fullPath = join(directory, entry.name);
|
|
69325
|
+
if (entry.isDirectory()) {
|
|
69326
|
+
if (!IGNORED_DIRECTORIES.has(entry.name)) await collectTypeScriptFilesInto(fullPath, results);
|
|
69327
|
+
continue;
|
|
69328
|
+
}
|
|
69329
|
+
if (!entry.isFile()) continue;
|
|
69330
|
+
const extension = extname(entry.name);
|
|
69331
|
+
if (extension === ".ts" || extension === ".tsx") results.push(fullPath);
|
|
69332
|
+
}
|
|
69333
|
+
}
|
|
69334
|
+
function parseBetterSolUsage(source, filePath) {
|
|
69335
|
+
let program;
|
|
69336
|
+
try {
|
|
69337
|
+
program = parseModule(filePath, source);
|
|
69338
|
+
} catch {
|
|
69339
|
+
return;
|
|
69340
|
+
}
|
|
69341
|
+
let hasCall = false;
|
|
69342
|
+
let hasProgramsObject = false;
|
|
69343
|
+
visitAst(program, (node) => {
|
|
69344
|
+
if (!isBetterSolCall(node)) return;
|
|
69345
|
+
hasCall = true;
|
|
69346
|
+
const firstArg = node.arguments[0];
|
|
69347
|
+
if (!isObjectExpression(firstArg)) return;
|
|
69348
|
+
if (isObjectExpression(getObjectProperty(firstArg, "programs"))) hasProgramsObject = true;
|
|
69349
|
+
});
|
|
69350
|
+
return hasCall ? {
|
|
69351
|
+
filePath,
|
|
69352
|
+
hasProgramsObject
|
|
69353
|
+
} : void 0;
|
|
69354
|
+
}
|
|
69355
|
+
function isBetterSolCall(node) {
|
|
69356
|
+
return isCallExpression(node) && isIdentifier(node.callee) && node.callee.name === "betterSol";
|
|
69357
|
+
}
|
|
69358
|
+
function visitAst(node, visit) {
|
|
69359
|
+
if (!isAstNode(node)) return;
|
|
69360
|
+
visit(node);
|
|
69361
|
+
for (const value of Object.values(node)) if (Array.isArray(value)) for (const item of value) visitAst(item, visit);
|
|
69362
|
+
else visitAst(value, visit);
|
|
69363
|
+
}
|
|
69364
|
+
function isAstNode(value) {
|
|
69365
|
+
if (typeof value !== "object" || value === null) return false;
|
|
69366
|
+
return typeof value.type === "string";
|
|
69367
|
+
}
|
|
69368
|
+
function moduleSpecifier(fromDirectory, toFile) {
|
|
69369
|
+
const normalized = removeExt(relative(fromDirectory, toFile)).split(sep).join("/");
|
|
69370
|
+
if (normalized.startsWith(".")) return normalized;
|
|
69371
|
+
return `./${normalized}`;
|
|
69372
|
+
}
|
|
69373
|
+
function relativePath(fromDirectory, toFile) {
|
|
69374
|
+
const value = relative(fromDirectory, toFile).split(sep).join("/");
|
|
69375
|
+
return value.length > 0 ? value : ".";
|
|
69376
|
+
}
|
|
69228
69377
|
function removeExt(path) {
|
|
69229
|
-
return path.replace(/\.
|
|
69378
|
+
return path.replace(/\.tsx?$/, "");
|
|
69379
|
+
}
|
|
69380
|
+
function getIdlName(idl) {
|
|
69381
|
+
if (typeof idl.metadata?.name === "string") return idl.metadata.name;
|
|
69382
|
+
const record = idl;
|
|
69383
|
+
return typeof record.name === "string" ? record.name : void 0;
|
|
69230
69384
|
}
|
|
69231
69385
|
//#endregion
|
|
69232
69386
|
//#region src/commands/login.ts
|
|
@@ -69328,7 +69482,7 @@ async function gitCommit() {
|
|
|
69328
69482
|
//#endregion
|
|
69329
69483
|
//#region src/index.ts
|
|
69330
69484
|
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.
|
|
69485
|
+
cli.name("better-sol").description("Write Solana programs in TypeScript. Run with npx @better-sol/cli@alpha").version("0.1.0-alpha.13");
|
|
69332
69486
|
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
69487
|
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
69488
|
cli.command("login").description("Save your compiler API key").argument("[apiKey]", "compiler API key").action((apiKey) => run(() => login(apiKey)));
|