@s2script/sdk 0.13.0 → 0.15.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.
- package/README.md +7 -0
- package/dist/cli.js +784 -303
- package/events.d.ts +19 -0
- package/package.json +1 -1
- package/plugin.d.ts +12 -1
package/dist/cli.js
CHANGED
|
@@ -668,8 +668,8 @@ var require_major = __commonJS({
|
|
|
668
668
|
"../../node_modules/semver/functions/major.js"(exports, module) {
|
|
669
669
|
"use strict";
|
|
670
670
|
var SemVer = require_semver();
|
|
671
|
-
var
|
|
672
|
-
module.exports =
|
|
671
|
+
var major2 = (a2, loose) => new SemVer(a2, loose).major;
|
|
672
|
+
module.exports = major2;
|
|
673
673
|
}
|
|
674
674
|
});
|
|
675
675
|
|
|
@@ -915,12 +915,12 @@ var require_coerce = __commonJS({
|
|
|
915
915
|
if (match === null) {
|
|
916
916
|
return null;
|
|
917
917
|
}
|
|
918
|
-
const
|
|
918
|
+
const major2 = match[2];
|
|
919
919
|
const minor = match[3] || "0";
|
|
920
920
|
const patch = match[4] || "0";
|
|
921
921
|
const prerelease = options.includePrerelease && match[5] ? `-${match[5]}` : "";
|
|
922
|
-
const
|
|
923
|
-
return parse(`${
|
|
922
|
+
const build3 = options.includePrerelease && match[6] ? `+${match[6]}` : "";
|
|
923
|
+
return parse(`${major2}.${minor}.${patch}${prerelease}${build3}`, options);
|
|
924
924
|
};
|
|
925
925
|
module.exports = coerce;
|
|
926
926
|
}
|
|
@@ -1991,7 +1991,7 @@ var require_semver2 = __commonJS({
|
|
|
1991
1991
|
var clean = require_clean();
|
|
1992
1992
|
var inc = require_inc();
|
|
1993
1993
|
var diff = require_diff();
|
|
1994
|
-
var
|
|
1994
|
+
var major2 = require_major();
|
|
1995
1995
|
var minor = require_minor();
|
|
1996
1996
|
var patch = require_patch();
|
|
1997
1997
|
var prerelease = require_prerelease();
|
|
@@ -2030,7 +2030,7 @@ var require_semver2 = __commonJS({
|
|
|
2030
2030
|
clean,
|
|
2031
2031
|
inc,
|
|
2032
2032
|
diff,
|
|
2033
|
-
major,
|
|
2033
|
+
major: major2,
|
|
2034
2034
|
minor,
|
|
2035
2035
|
patch,
|
|
2036
2036
|
prerelease,
|
|
@@ -2076,10 +2076,10 @@ var require_semver2 = __commonJS({
|
|
|
2076
2076
|
});
|
|
2077
2077
|
|
|
2078
2078
|
// src/commands/build.ts
|
|
2079
|
-
import { resolve as
|
|
2079
|
+
import { resolve as resolve11 } from "node:path";
|
|
2080
2080
|
|
|
2081
2081
|
// src/build.ts
|
|
2082
|
-
import * as
|
|
2082
|
+
import * as esbuild2 from "esbuild";
|
|
2083
2083
|
|
|
2084
2084
|
// ../../node_modules/fflate/esm/index.mjs
|
|
2085
2085
|
import { createRequire } from "module";
|
|
@@ -3068,13 +3068,13 @@ function unzipSync(data, opts) {
|
|
|
3068
3068
|
}
|
|
3069
3069
|
|
|
3070
3070
|
// src/build.ts
|
|
3071
|
-
import { readFileSync as
|
|
3072
|
-
import { resolve as
|
|
3071
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, rmSync as rmSync2 } from "node:fs";
|
|
3072
|
+
import { resolve as resolve10, join as join11, sep as sep2, basename } from "node:path";
|
|
3073
3073
|
|
|
3074
3074
|
// src/typecheck/typecheck.ts
|
|
3075
3075
|
import ts from "typescript";
|
|
3076
|
-
import { existsSync as
|
|
3077
|
-
import { join as
|
|
3076
|
+
import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync6, writeFileSync, rmSync, mkdtempSync } from "node:fs";
|
|
3077
|
+
import { join as join7, resolve as resolve6 } from "node:path";
|
|
3078
3078
|
import { tmpdir } from "node:os";
|
|
3079
3079
|
|
|
3080
3080
|
// src/packages-resolve.ts
|
|
@@ -3414,6 +3414,11 @@ function readWorkspace(root) {
|
|
|
3414
3414
|
}
|
|
3415
3415
|
return { workspace: { root: absRoot, pkg, plugins, libs }, problems };
|
|
3416
3416
|
}
|
|
3417
|
+
function memberForDir(ws, dir) {
|
|
3418
|
+
const abs = toPosix(resolve2(dir));
|
|
3419
|
+
for (const m of [...ws.plugins, ...ws.libs]) if (toPosix(m.dir) === abs) return m;
|
|
3420
|
+
return null;
|
|
3421
|
+
}
|
|
3417
3422
|
|
|
3418
3423
|
// src/publishes.ts
|
|
3419
3424
|
import { createHash } from "node:crypto";
|
|
@@ -3630,32 +3635,156 @@ function resolveSiblingContracts(pluginDir, deps) {
|
|
|
3630
3635
|
return { siblings, shadowedCopies };
|
|
3631
3636
|
}
|
|
3632
3637
|
|
|
3638
|
+
// src/libraries.ts
|
|
3639
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "node:fs";
|
|
3640
|
+
import { join as join6, resolve as resolve5 } from "node:path";
|
|
3641
|
+
function packageKind(pkg) {
|
|
3642
|
+
const k = pkg.s2script?.kind ?? "plugin";
|
|
3643
|
+
if (k !== "plugin" && k !== "library") {
|
|
3644
|
+
throw new Error(`unknown s2script.kind ${JSON.stringify(k)} \u2014 expected "plugin" or "library"`);
|
|
3645
|
+
}
|
|
3646
|
+
return k;
|
|
3647
|
+
}
|
|
3648
|
+
function librariesRoot(pluginDir) {
|
|
3649
|
+
return join6(pluginDir, ".s2script", "libs");
|
|
3650
|
+
}
|
|
3651
|
+
function localLibraryDir(pluginDir, name) {
|
|
3652
|
+
const segs = name.split("/");
|
|
3653
|
+
if (segs.some((s) => s === "" || s === "." || s === "..")) return null;
|
|
3654
|
+
const p = join6(librariesRoot(pluginDir), ...segs);
|
|
3655
|
+
return existsSync5(join6(p, "index.d.ts")) ? p : null;
|
|
3656
|
+
}
|
|
3657
|
+
function resolveLibrarySibling(pluginDir, name) {
|
|
3658
|
+
const absDir = resolve5(pluginDir);
|
|
3659
|
+
const root = findWorkspaceRoot(absDir);
|
|
3660
|
+
if (root === null) return null;
|
|
3661
|
+
const scan = scanWorkspace(root);
|
|
3662
|
+
const ws = scan.workspace;
|
|
3663
|
+
if (memberForDir(ws, absDir) === null) return null;
|
|
3664
|
+
const named2 = [...ws.libs, ...ws.plugins].filter((m) => m.name === name);
|
|
3665
|
+
let lib;
|
|
3666
|
+
for (const m of named2) {
|
|
3667
|
+
let kind;
|
|
3668
|
+
try {
|
|
3669
|
+
kind = packageKind(m.pkg);
|
|
3670
|
+
} catch (e) {
|
|
3671
|
+
throw new Error(`library ${name} (workspace member at ${m.relDir}): ${e.message}`);
|
|
3672
|
+
}
|
|
3673
|
+
if (kind === "library") {
|
|
3674
|
+
lib = m;
|
|
3675
|
+
break;
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3678
|
+
if (lib === void 0) {
|
|
3679
|
+
if (scan.problems.length > 0) {
|
|
3680
|
+
console.warn(
|
|
3681
|
+
`WARN: ${name}: no workspace sibling found, but ${scan.problems.length} workspace member${scan.problems.length === 1 ? "" : "s"} could not be read \u2014 one of them may be this library, in which case it will be reported as missing instead. Fix:
|
|
3682
|
+
` + scan.problems.join("\n ")
|
|
3683
|
+
);
|
|
3684
|
+
}
|
|
3685
|
+
return null;
|
|
3686
|
+
}
|
|
3687
|
+
const typesRel = lib.pkg.types;
|
|
3688
|
+
if (typeof typesRel !== "string" || typesRel === "") {
|
|
3689
|
+
throw new Error(
|
|
3690
|
+
`library ${name} (workspace sibling at ${lib.relDir}) has no "types" in its package.json`
|
|
3691
|
+
);
|
|
3692
|
+
}
|
|
3693
|
+
const typesPath = resolve5(lib.dir, typesRel);
|
|
3694
|
+
if (!existsSync5(typesPath)) {
|
|
3695
|
+
throw new Error(
|
|
3696
|
+
`library ${name} (workspace sibling at ${lib.relDir}) types file not found: ${typesRel}`
|
|
3697
|
+
);
|
|
3698
|
+
}
|
|
3699
|
+
return { dir: lib.dir, typesPath, version: lib.version };
|
|
3700
|
+
}
|
|
3701
|
+
function resolveLibraries(pluginDir, declared) {
|
|
3702
|
+
const paths = {};
|
|
3703
|
+
const manifests = {};
|
|
3704
|
+
const missing = [];
|
|
3705
|
+
const siblingDirs = {};
|
|
3706
|
+
for (const name of Object.keys(declared)) {
|
|
3707
|
+
const dir = localLibraryDir(pluginDir, name);
|
|
3708
|
+
if (dir !== null) {
|
|
3709
|
+
paths[name] = [join6(dir, "index.d.ts")];
|
|
3710
|
+
let version = "0.0.0";
|
|
3711
|
+
let apiVersion = "1.x";
|
|
3712
|
+
try {
|
|
3713
|
+
const m = JSON.parse(readFileSync5(join6(dir, "package.json"), "utf8"));
|
|
3714
|
+
if (typeof m.version === "string") version = m.version;
|
|
3715
|
+
if (typeof m.s2script?.apiVersion === "string") apiVersion = m.s2script.apiVersion;
|
|
3716
|
+
} catch {
|
|
3717
|
+
}
|
|
3718
|
+
manifests[name] = { version, apiVersion, source: "vendored" };
|
|
3719
|
+
continue;
|
|
3720
|
+
}
|
|
3721
|
+
const sib = resolveLibrarySibling(pluginDir, name);
|
|
3722
|
+
if (sib !== null) {
|
|
3723
|
+
paths[name] = [sib.typesPath];
|
|
3724
|
+
manifests[name] = { version: sib.version, apiVersion: "", source: "workspace" };
|
|
3725
|
+
siblingDirs[name] = sib.dir;
|
|
3726
|
+
continue;
|
|
3727
|
+
}
|
|
3728
|
+
missing.push(name);
|
|
3729
|
+
}
|
|
3730
|
+
return { paths, missing, manifests, siblingDirs };
|
|
3731
|
+
}
|
|
3732
|
+
function major(apiVersion) {
|
|
3733
|
+
const n3 = Number.parseInt(apiVersion.split(".")[0] ?? "1", 10);
|
|
3734
|
+
return Number.isNaN(n3) ? 1 : n3;
|
|
3735
|
+
}
|
|
3736
|
+
function assertLibrariesResolved(pluginDir, declared, sdkApiVersion) {
|
|
3737
|
+
const reserved = Object.keys(declared).filter((n3) => n3 === "@s2script" || n3.startsWith("@s2script/"));
|
|
3738
|
+
if (reserved.length > 0) {
|
|
3739
|
+
throw new Error(
|
|
3740
|
+
`s2script.libraries declares ${reserved.map((n3) => JSON.stringify(n3)).join(", ")} \u2014 the @s2script/* scope is reserved and always resolved as a runtime builtin, so it can never be a bundled library`
|
|
3741
|
+
);
|
|
3742
|
+
}
|
|
3743
|
+
const resolved = resolveLibraries(pluginDir, declared);
|
|
3744
|
+
if (resolved.missing.length) {
|
|
3745
|
+
throw new Error(
|
|
3746
|
+
`declared in s2script.libraries but not vendored under .s2script/libs and no workspace sibling found:
|
|
3747
|
+
` + resolved.missing.map((n3) => ` ${n3} \u2014 run \`s2s add ${n3}\``).join("\n")
|
|
3748
|
+
);
|
|
3749
|
+
}
|
|
3750
|
+
const sdkMajor = major(sdkApiVersion);
|
|
3751
|
+
for (const [name, m] of Object.entries(resolved.manifests)) {
|
|
3752
|
+
if (m.source === "workspace") continue;
|
|
3753
|
+
if (major(m.apiVersion) > sdkMajor) {
|
|
3754
|
+
throw new Error(
|
|
3755
|
+
`library ${name}@${m.version} was built against apiVersion ${m.apiVersion}, newer than this SDK's ${sdkApiVersion} \u2014 upgrade @s2script/sdk`
|
|
3756
|
+
);
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
return resolved;
|
|
3760
|
+
}
|
|
3761
|
+
|
|
3633
3762
|
// src/typecheck/typecheck.ts
|
|
3634
3763
|
function localDeclarationFiles(pluginDir) {
|
|
3635
|
-
const srcDir =
|
|
3636
|
-
if (!
|
|
3637
|
-
return readdirSync2(srcDir).filter((f) => f.endsWith(".d.ts")).map((f) =>
|
|
3764
|
+
const srcDir = join7(pluginDir, "src");
|
|
3765
|
+
if (!existsSync6(srcDir)) return [];
|
|
3766
|
+
return readdirSync2(srcDir).filter((f) => f.endsWith(".d.ts")).map((f) => join7(srcDir, f));
|
|
3638
3767
|
}
|
|
3639
3768
|
function generatedDeclarationFiles(pluginDir) {
|
|
3640
|
-
const gd =
|
|
3641
|
-
return
|
|
3769
|
+
const gd = join7(pluginDir, ".s2script", "gamedata.d.ts");
|
|
3770
|
+
return existsSync6(gd) ? [gd] : [];
|
|
3642
3771
|
}
|
|
3643
3772
|
function declaredModules(dtsFiles) {
|
|
3644
3773
|
const out = /* @__PURE__ */ new Set();
|
|
3645
3774
|
for (const f of dtsFiles) {
|
|
3646
|
-
const body =
|
|
3775
|
+
const body = readFileSync6(f, "utf8");
|
|
3647
3776
|
for (const m of body.matchAll(/declare\s+module\s+["']([^"']+)["']/g)) out.add(m[1]);
|
|
3648
3777
|
}
|
|
3649
3778
|
return out;
|
|
3650
3779
|
}
|
|
3651
3780
|
function typecheckPlugin(pluginDir, opts) {
|
|
3652
|
-
const absDir =
|
|
3653
|
-
const packagesDir = opts?.packagesDir ?
|
|
3654
|
-
const pkg = JSON.parse(
|
|
3781
|
+
const absDir = resolve6(pluginDir);
|
|
3782
|
+
const packagesDir = opts?.packagesDir ? resolve6(opts.packagesDir) : resolvePackagesDir({ pluginDir: absDir });
|
|
3783
|
+
const pkg = JSON.parse(readFileSync6(join7(absDir, "package.json"), "utf8"));
|
|
3655
3784
|
const s2 = pkg.s2script ?? {};
|
|
3656
3785
|
const entryRel = s2.main ?? pkg.main;
|
|
3657
|
-
if (!entryRel) throw new Error(`typecheckPlugin: no entry point in ${
|
|
3658
|
-
const entry =
|
|
3786
|
+
if (!entryRel) throw new Error(`typecheckPlugin: no entry point in ${join7(absDir, "package.json")}`);
|
|
3787
|
+
const entry = resolve6(absDir, entryRel);
|
|
3659
3788
|
const isAlwaysResolved = (d) => d.startsWith("@s2script/sdk/") || d === "@s2script/cs2" || d.startsWith("@s2script/cs2/");
|
|
3660
3789
|
const localDts = localDeclarationFiles(absDir);
|
|
3661
3790
|
const locallyDeclared = declaredModules(localDts);
|
|
@@ -3674,13 +3803,15 @@ function typecheckPlugin(pluginDir, opts) {
|
|
|
3674
3803
|
const p = localContractPath(absDir, d);
|
|
3675
3804
|
if (p !== null) contractPaths[d] = [p];
|
|
3676
3805
|
}
|
|
3806
|
+
const libraryPaths = resolveLibraries(absDir, s2.libraries ?? {}).paths;
|
|
3807
|
+
const libraryNames = new Set(Object.keys(s2.libraries ?? {}));
|
|
3677
3808
|
const deps = [
|
|
3678
3809
|
...Object.keys(s2.pluginDependencies ?? {}),
|
|
3679
3810
|
...Object.keys(s2.optionalPluginDependencies ?? {})
|
|
3680
3811
|
// Never stub a module the plugin declares itself — a shorthand `declare module "X";` and a
|
|
3681
3812
|
// full `declare module "X" { … }` for the same X collide.
|
|
3682
3813
|
].filter(
|
|
3683
|
-
(d) => !isAlwaysResolved(d) && !locallyDeclared.has(d) && contractPaths[d] === void 0 && !siblings.has(d)
|
|
3814
|
+
(d) => !isAlwaysResolved(d) && !locallyDeclared.has(d) && contractPaths[d] === void 0 && !siblings.has(d) && !libraryNames.has(d)
|
|
3684
3815
|
);
|
|
3685
3816
|
const options = {
|
|
3686
3817
|
// Accept explicit `.ts` import extensions (node type-stripping requires them for source-to-source
|
|
@@ -3698,19 +3829,20 @@ function typecheckPlugin(pluginDir, opts) {
|
|
|
3698
3829
|
// subpath. tsc picks the longest matching prefix, so this wins for cs2 subpath imports.
|
|
3699
3830
|
"@s2script/cs2/*": ["cs2/*.d.ts"],
|
|
3700
3831
|
"@s2script/*": ["*/index.d.ts"],
|
|
3701
|
-
...contractPaths
|
|
3832
|
+
...contractPaths,
|
|
3833
|
+
...libraryPaths
|
|
3702
3834
|
}
|
|
3703
3835
|
};
|
|
3704
3836
|
const rootNames = [
|
|
3705
3837
|
entry,
|
|
3706
|
-
|
|
3838
|
+
join7(packagesDir, "sdk", "globals.d.ts"),
|
|
3707
3839
|
...localDts,
|
|
3708
3840
|
...generatedDeclarationFiles(absDir)
|
|
3709
3841
|
];
|
|
3710
|
-
const tmp = mkdtempSync(
|
|
3842
|
+
const tmp = mkdtempSync(join7(tmpdir(), "s2tc-"));
|
|
3711
3843
|
try {
|
|
3712
3844
|
if (deps.length) {
|
|
3713
|
-
const stub =
|
|
3845
|
+
const stub = join7(tmp, "ambient.d.ts");
|
|
3714
3846
|
writeFileSync(stub, deps.map((d) => `declare module ${JSON.stringify(d)};`).join("\n") + "\n");
|
|
3715
3847
|
rootNames.push(stub);
|
|
3716
3848
|
}
|
|
@@ -3840,61 +3972,70 @@ function validateDecl(full, decl, typeStr, errs) {
|
|
|
3840
3972
|
var HOST_API_VERSION_MAJOR = 2;
|
|
3841
3973
|
var STAMPED_API_VERSION = `${HOST_API_VERSION_MAJOR}.x`;
|
|
3842
3974
|
|
|
3843
|
-
// src/
|
|
3844
|
-
import
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3975
|
+
// src/npm-deps-gate.ts
|
|
3976
|
+
import { lstatSync, realpathSync } from "node:fs";
|
|
3977
|
+
import { dirname as dirname3, join as join8, resolve as resolve7, sep } from "node:path";
|
|
3978
|
+
function findInNodeModules(startDir, dep) {
|
|
3979
|
+
const segs = dep.split("/");
|
|
3980
|
+
let dir = resolve7(startDir);
|
|
3981
|
+
for (; ; ) {
|
|
3982
|
+
const candidate = join8(dir, "node_modules", ...segs);
|
|
3983
|
+
try {
|
|
3984
|
+
lstatSync(candidate);
|
|
3985
|
+
return candidate;
|
|
3986
|
+
} catch {
|
|
3987
|
+
}
|
|
3988
|
+
const parent = dirname3(dir);
|
|
3989
|
+
if (parent === dir) return null;
|
|
3990
|
+
dir = parent;
|
|
3991
|
+
}
|
|
3848
3992
|
}
|
|
3849
|
-
function
|
|
3850
|
-
const
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
if (ts2.isCallExpression(node) && ts2.isPropertyAccessExpression(node.expression)) {
|
|
3858
|
-
const method = node.expression.name.text;
|
|
3859
|
-
if (method === "publish" || method === "use" || method === "tryUse") {
|
|
3860
|
-
const recv = checker.getTypeAtLocation(node.expression.expression);
|
|
3861
|
-
if (isPluginContext(recv)) {
|
|
3862
|
-
const arg0 = node.arguments[0];
|
|
3863
|
-
if (method === "publish") {
|
|
3864
|
-
if (arg0 !== void 0 && ts2.isStringLiteralLike(arg0)) {
|
|
3865
|
-
out.publishNames.push(arg0.text);
|
|
3866
|
-
} else {
|
|
3867
|
-
const { line } = sf.getLineAndCharacterOfPosition(node.getStart());
|
|
3868
|
-
out.dynamicPublishSites.push(`${sf.fileName}:${line + 1}`);
|
|
3869
|
-
}
|
|
3870
|
-
} else if (arg0 !== void 0 && ts2.isStringLiteralLike(arg0)) {
|
|
3871
|
-
out.useNames.push(arg0.text);
|
|
3872
|
-
}
|
|
3873
|
-
}
|
|
3874
|
-
}
|
|
3875
|
-
}
|
|
3876
|
-
ts2.forEachChild(node, visit);
|
|
3877
|
-
};
|
|
3878
|
-
visit(sf);
|
|
3993
|
+
function isWorkspaceLinked(pluginDir, dep) {
|
|
3994
|
+
const found = findInNodeModules(pluginDir, dep);
|
|
3995
|
+
if (found === null) return false;
|
|
3996
|
+
let real;
|
|
3997
|
+
try {
|
|
3998
|
+
real = realpathSync(found);
|
|
3999
|
+
} catch {
|
|
4000
|
+
return false;
|
|
3879
4001
|
}
|
|
3880
|
-
|
|
3881
|
-
out.useNames = [...new Set(out.useNames)];
|
|
3882
|
-
return out;
|
|
4002
|
+
return !real.split(sep).includes("node_modules");
|
|
3883
4003
|
}
|
|
4004
|
+
function assertNoNpmRuntimeDeps(pkg, pluginDir) {
|
|
4005
|
+
const offenders = [];
|
|
4006
|
+
for (const [dep, range] of Object.entries(pkg.dependencies ?? {})) {
|
|
4007
|
+
if (dep.startsWith("@s2script/")) continue;
|
|
4008
|
+
if (typeof range === "string" && (range.startsWith("file:") || range.startsWith("workspace:"))) continue;
|
|
4009
|
+
if (isWorkspaceLinked(pluginDir, dep)) continue;
|
|
4010
|
+
offenders.push(dep);
|
|
4011
|
+
}
|
|
4012
|
+
if (!offenders.length) return;
|
|
4013
|
+
throw new Error(
|
|
4014
|
+
`runtime dependenc${offenders.length === 1 ? "y" : "ies"} ` + offenders.map((d) => JSON.stringify(d)).join(", ") + ` ${offenders.length === 1 ? "is" : "are"} not s2script librar${offenders.length === 1 ? "y" : "ies"}.
|
|
4015
|
+
Plugins run in bare V8 \u2014 no Node APIs, no npm runtime. A package that touches
|
|
4016
|
+
fs/net/process builds green and fails on a live server.
|
|
4017
|
+
Use s2script.libraries (\`s2s add <pkg>\`), or vendor it as a workspace package.`
|
|
4018
|
+
);
|
|
4019
|
+
}
|
|
4020
|
+
|
|
4021
|
+
// src/build-library.ts
|
|
4022
|
+
import * as esbuild from "esbuild";
|
|
4023
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync2, mkdirSync, existsSync as existsSync8, statSync as statSync3 } from "node:fs";
|
|
4024
|
+
import { resolve as resolve9, join as join10 } from "node:path";
|
|
3884
4025
|
|
|
3885
4026
|
// src/lint/lint.ts
|
|
3886
4027
|
import { ESLint } from "eslint";
|
|
3887
|
-
import { existsSync as
|
|
3888
|
-
import { dirname as
|
|
4028
|
+
import { existsSync as existsSync7, readdirSync as readdirSync3 } from "node:fs";
|
|
4029
|
+
import { dirname as dirname4, join as join9, resolve as resolve8 } from "node:path";
|
|
3889
4030
|
import s2lint from "@s2script/eslint-plugin";
|
|
3890
4031
|
var CONFIG_FILES = ["eslint.config.js", "eslint.config.mjs", "eslint.config.cjs", "eslint.config.ts"];
|
|
3891
4032
|
function ownConfigDir(pluginDir) {
|
|
3892
4033
|
const stopAt = findWorkspaceRoot(pluginDir);
|
|
3893
4034
|
let dir = pluginDir;
|
|
3894
4035
|
for (; ; ) {
|
|
3895
|
-
if (CONFIG_FILES.some((f) =>
|
|
4036
|
+
if (CONFIG_FILES.some((f) => existsSync7(join9(dir, f)))) return dir;
|
|
3896
4037
|
if (stopAt === null || dir === stopAt) return null;
|
|
3897
|
-
const parent =
|
|
4038
|
+
const parent = dirname4(dir);
|
|
3898
4039
|
if (parent === dir) return null;
|
|
3899
4040
|
dir = parent;
|
|
3900
4041
|
}
|
|
@@ -3909,14 +4050,14 @@ function collectTsFiles(dir) {
|
|
|
3909
4050
|
const out = [];
|
|
3910
4051
|
for (const e of entries) {
|
|
3911
4052
|
if (e.name === "node_modules" || e.name.startsWith(".")) continue;
|
|
3912
|
-
const full =
|
|
4053
|
+
const full = join9(dir, e.name);
|
|
3913
4054
|
if (e.isDirectory()) out.push(...collectTsFiles(full));
|
|
3914
|
-
else if (e.isFile() && e.name.endsWith(".ts")) out.push(full);
|
|
4055
|
+
else if (e.isFile() && e.name.endsWith(".ts") && !e.name.endsWith(".d.ts")) out.push(full);
|
|
3915
4056
|
}
|
|
3916
4057
|
return out;
|
|
3917
4058
|
}
|
|
3918
4059
|
async function lintPlugin(pluginDir, program) {
|
|
3919
|
-
const absDir =
|
|
4060
|
+
const absDir = resolve8(pluginDir);
|
|
3920
4061
|
const configDir = ownConfigDir(absDir);
|
|
3921
4062
|
const hasOwnConfig = configDir !== null;
|
|
3922
4063
|
const eslint = hasOwnConfig ? new ESLint({ cwd: configDir, errorOnUnmatchedPattern: false, warnIgnored: false }) : new ESLint({
|
|
@@ -3935,6 +4076,126 @@ async function lintPlugin(pluginDir, program) {
|
|
|
3935
4076
|
return { ok: errorCount === 0, output, errorCount };
|
|
3936
4077
|
}
|
|
3937
4078
|
|
|
4079
|
+
// src/build-library.ts
|
|
4080
|
+
async function buildLibrary(dir, packagesDir) {
|
|
4081
|
+
const absDir = resolve9(dir);
|
|
4082
|
+
const pkgPath = join10(absDir, "package.json");
|
|
4083
|
+
const pkg = JSON.parse(readFileSync7(pkgPath, "utf8"));
|
|
4084
|
+
const s2 = pkg.s2script ?? {};
|
|
4085
|
+
if (s2.pluginDependencies || s2.optionalPluginDependencies) {
|
|
4086
|
+
throw new Error(
|
|
4087
|
+
"a library may not declare pluginDependencies/optionalPluginDependencies \u2014 an inter-plugin proxy belongs to a loaded plugin's ledger, not to build-time code"
|
|
4088
|
+
);
|
|
4089
|
+
}
|
|
4090
|
+
if (s2.publishes) {
|
|
4091
|
+
throw new Error("a library may not declare publishes \u2014 publishes is a plugin's runtime contract");
|
|
4092
|
+
}
|
|
4093
|
+
const typesRel = pkg.types ?? pkg.typings;
|
|
4094
|
+
if (typeof typesRel !== "string" || !typesRel.endsWith(".d.ts")) {
|
|
4095
|
+
throw new Error('a library must set "types" to a .d.ts \u2014 consumers vendor it to typecheck against');
|
|
4096
|
+
}
|
|
4097
|
+
const typesPath = resolve9(absDir, typesRel);
|
|
4098
|
+
if (!existsSync8(typesPath) || !statSync3(typesPath).isFile() || statSync3(typesPath).size === 0) {
|
|
4099
|
+
throw new Error(`types file is missing or empty: ${typesRel}`);
|
|
4100
|
+
}
|
|
4101
|
+
assertNoNpmRuntimeDeps(pkg, absDir);
|
|
4102
|
+
const librariesResolved = assertLibrariesResolved(absDir, s2.libraries ?? {}, STAMPED_API_VERSION);
|
|
4103
|
+
const tc = typecheckPlugin(absDir, packagesDir !== void 0 ? { packagesDir } : void 0);
|
|
4104
|
+
if (!tc.ok) {
|
|
4105
|
+
throw new Error(`typecheck failed (${tc.diagnostics.length} error(s)):
|
|
4106
|
+
${formatDiagnostics(tc.diagnostics)}`);
|
|
4107
|
+
}
|
|
4108
|
+
const lint = await lintPlugin(absDir, tc.program);
|
|
4109
|
+
if (!lint.ok) {
|
|
4110
|
+
throw new Error(`lint failed (${lint.errorCount} error(s)):
|
|
4111
|
+
${lint.output}`);
|
|
4112
|
+
}
|
|
4113
|
+
if (lint.output.trim().length > 0) console.warn(lint.output);
|
|
4114
|
+
const entryRelative = s2.main ?? pkg.main;
|
|
4115
|
+
if (!entryRelative) throw new Error(`buildLibrary: no entry point in ${pkgPath} (set s2script.main or main)`);
|
|
4116
|
+
const result = await esbuild.build({
|
|
4117
|
+
entryPoints: [join10(absDir, entryRelative)],
|
|
4118
|
+
bundle: true,
|
|
4119
|
+
platform: "neutral",
|
|
4120
|
+
format: "cjs",
|
|
4121
|
+
// Builtins resolve in the CONSUMER's context at runtime, so they stay external
|
|
4122
|
+
// through both bundles. Everything else — including this library's own libraries
|
|
4123
|
+
// — is inlined, which is what makes a .s2lib self-contained.
|
|
4124
|
+
external: ["@s2script/*"],
|
|
4125
|
+
target: "es2020",
|
|
4126
|
+
mainFields: ["module", "main"],
|
|
4127
|
+
// A vendored library's directory is already named for its package, so `nodePaths` alone
|
|
4128
|
+
// resolves it. A WORKSPACE-sibling library (librariesResolved.siblingDirs) is not, hence the
|
|
4129
|
+
// alias — same reasoning `build.ts` applies to a plugin's own library imports.
|
|
4130
|
+
nodePaths: [librariesRoot(absDir)],
|
|
4131
|
+
alias: librariesResolved.siblingDirs,
|
|
4132
|
+
write: false
|
|
4133
|
+
});
|
|
4134
|
+
const manifest = {
|
|
4135
|
+
kind: "library",
|
|
4136
|
+
id: pkg.name,
|
|
4137
|
+
version: pkg.version,
|
|
4138
|
+
apiVersion: STAMPED_API_VERSION,
|
|
4139
|
+
main: "index.js",
|
|
4140
|
+
types: "index.d.ts"
|
|
4141
|
+
};
|
|
4142
|
+
const sanitized = String(pkg.name).replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
4143
|
+
const outDir = join10(absDir, "dist");
|
|
4144
|
+
mkdirSync(outDir, { recursive: true });
|
|
4145
|
+
const outPath = join10(outDir, `${sanitized}.s2lib`);
|
|
4146
|
+
writeFileSync2(
|
|
4147
|
+
outPath,
|
|
4148
|
+
zipSync({
|
|
4149
|
+
"manifest.json": Buffer.from(JSON.stringify(manifest, null, 2)),
|
|
4150
|
+
"index.js": Buffer.from(result.outputFiles[0].text),
|
|
4151
|
+
"index.d.ts": readFileSync7(typesPath)
|
|
4152
|
+
})
|
|
4153
|
+
);
|
|
4154
|
+
return outPath;
|
|
4155
|
+
}
|
|
4156
|
+
|
|
4157
|
+
// src/publish-scan.ts
|
|
4158
|
+
import ts2 from "typescript";
|
|
4159
|
+
function isPluginContext(type) {
|
|
4160
|
+
const sym = type.getSymbol() ?? type.aliasSymbol;
|
|
4161
|
+
return sym?.getName() === "PluginContext";
|
|
4162
|
+
}
|
|
4163
|
+
function scanPluginProgram(program, pluginDir) {
|
|
4164
|
+
const checker = program.getTypeChecker();
|
|
4165
|
+
const out = { publishNames: [], dynamicPublishSites: [], useNames: [] };
|
|
4166
|
+
const dirPrefix = pluginDir.replace(/\\/g, "/").replace(/\/+$/, "") + "/";
|
|
4167
|
+
for (const sf of program.getSourceFiles()) {
|
|
4168
|
+
if (sf.isDeclarationFile) continue;
|
|
4169
|
+
if (!sf.fileName.replace(/\\/g, "/").startsWith(dirPrefix)) continue;
|
|
4170
|
+
const visit = (node) => {
|
|
4171
|
+
if (ts2.isCallExpression(node) && ts2.isPropertyAccessExpression(node.expression)) {
|
|
4172
|
+
const method = node.expression.name.text;
|
|
4173
|
+
if (method === "publish" || method === "use" || method === "tryUse") {
|
|
4174
|
+
const recv = checker.getTypeAtLocation(node.expression.expression);
|
|
4175
|
+
if (isPluginContext(recv)) {
|
|
4176
|
+
const arg0 = node.arguments[0];
|
|
4177
|
+
if (method === "publish") {
|
|
4178
|
+
if (arg0 !== void 0 && ts2.isStringLiteralLike(arg0)) {
|
|
4179
|
+
out.publishNames.push(arg0.text);
|
|
4180
|
+
} else {
|
|
4181
|
+
const { line } = sf.getLineAndCharacterOfPosition(node.getStart());
|
|
4182
|
+
out.dynamicPublishSites.push(`${sf.fileName}:${line + 1}`);
|
|
4183
|
+
}
|
|
4184
|
+
} else if (arg0 !== void 0 && ts2.isStringLiteralLike(arg0)) {
|
|
4185
|
+
out.useNames.push(arg0.text);
|
|
4186
|
+
}
|
|
4187
|
+
}
|
|
4188
|
+
}
|
|
4189
|
+
}
|
|
4190
|
+
ts2.forEachChild(node, visit);
|
|
4191
|
+
};
|
|
4192
|
+
visit(sf);
|
|
4193
|
+
}
|
|
4194
|
+
out.publishNames = [...new Set(out.publishNames)];
|
|
4195
|
+
out.useNames = [...new Set(out.useNames)];
|
|
4196
|
+
return out;
|
|
4197
|
+
}
|
|
4198
|
+
|
|
3938
4199
|
// src/gamedata/types.ts
|
|
3939
4200
|
var PLATFORM = "linuxsteamrt64";
|
|
3940
4201
|
var ARG_KINDS = ["bool", "int", "float", "string", "vector", "entity"];
|
|
@@ -4189,9 +4450,12 @@ function stripJsonComments(src) {
|
|
|
4189
4450
|
|
|
4190
4451
|
// src/build.ts
|
|
4191
4452
|
async function buildPlugin(dir, packagesDir) {
|
|
4192
|
-
const absDir =
|
|
4193
|
-
const pkgPath =
|
|
4194
|
-
const pkg = JSON.parse(
|
|
4453
|
+
const absDir = resolve10(dir);
|
|
4454
|
+
const pkgPath = join11(absDir, "package.json");
|
|
4455
|
+
const pkg = JSON.parse(readFileSync8(pkgPath, "utf8"));
|
|
4456
|
+
if (packageKind(pkg) === "library") {
|
|
4457
|
+
throw new Error(`${pkgPath} is s2script.kind="library" \u2014 build it with buildLibrary/buildPackage`);
|
|
4458
|
+
}
|
|
4195
4459
|
const s2 = pkg.s2script ?? {};
|
|
4196
4460
|
const config = s2.config ?? void 0;
|
|
4197
4461
|
if (config !== void 0) {
|
|
@@ -4199,11 +4463,25 @@ async function buildPlugin(dir, packagesDir) {
|
|
|
4199
4463
|
if (cfgErrs.length) throw new Error(`invalid s2script.config:
|
|
4200
4464
|
${cfgErrs.join("\n ")}`);
|
|
4201
4465
|
}
|
|
4466
|
+
assertNoNpmRuntimeDeps(pkg, absDir);
|
|
4467
|
+
const libraries = s2.libraries ?? {};
|
|
4468
|
+
const pluginDepNames = /* @__PURE__ */ new Set([
|
|
4469
|
+
...Object.keys(s2.pluginDependencies ?? {}),
|
|
4470
|
+
...Object.keys(s2.optionalPluginDependencies ?? {})
|
|
4471
|
+
]);
|
|
4472
|
+
for (const name2 of Object.keys(libraries)) {
|
|
4473
|
+
if (pluginDepNames.has(name2)) {
|
|
4474
|
+
throw new Error(
|
|
4475
|
+
`${JSON.stringify(name2)} is declared in BOTH s2script.libraries and s2script.pluginDependencies/optionalPluginDependencies \u2014 pick one: a library is build-time code bundled into this .s2sp, an inter-plugin dependency is a runtime proxy resolved by the host at load; the two cannot share a name`
|
|
4476
|
+
);
|
|
4477
|
+
}
|
|
4478
|
+
}
|
|
4479
|
+
const librariesResolved = assertLibrariesResolved(absDir, libraries, STAMPED_API_VERSION);
|
|
4202
4480
|
const permissions = Array.isArray(s2.permissions) ? s2.permissions : [];
|
|
4203
4481
|
let gamedata;
|
|
4204
4482
|
if (typeof s2.gamedata === "string") {
|
|
4205
|
-
const gdPath =
|
|
4206
|
-
const dirPrefix = absDir.endsWith(
|
|
4483
|
+
const gdPath = resolve10(absDir, s2.gamedata);
|
|
4484
|
+
const dirPrefix = absDir.endsWith(sep2) ? absDir : absDir + sep2;
|
|
4207
4485
|
if (gdPath !== absDir && !gdPath.startsWith(dirPrefix)) {
|
|
4208
4486
|
throw new Error(
|
|
4209
4487
|
`s2script.gamedata escapes the plugin directory: ${JSON.stringify(s2.gamedata)} resolves to ${gdPath}`
|
|
@@ -4217,7 +4495,7 @@ async function buildPlugin(dir, packagesDir) {
|
|
|
4217
4495
|
`s2script.gamedata must be named '${unscoped}.gamedata.jsonc' (after the plugin name without its scope, like the framework's own core.gamedata.jsonc), but is '${actualBase}'`
|
|
4218
4496
|
);
|
|
4219
4497
|
}
|
|
4220
|
-
const raw = stripJsonComments(
|
|
4498
|
+
const raw = stripJsonComments(readFileSync8(gdPath, "utf8"));
|
|
4221
4499
|
try {
|
|
4222
4500
|
gamedata = JSON.parse(raw);
|
|
4223
4501
|
} catch (e) {
|
|
@@ -4226,11 +4504,11 @@ async function buildPlugin(dir, packagesDir) {
|
|
|
4226
4504
|
const gdErrs = validatePluginGamedata(gamedata, { permissions });
|
|
4227
4505
|
if (gdErrs.length) throw new Error(`invalid gamedata:
|
|
4228
4506
|
${gdErrs.join("\n ")}`);
|
|
4229
|
-
const genDir =
|
|
4230
|
-
|
|
4231
|
-
|
|
4507
|
+
const genDir = join11(absDir, ".s2script");
|
|
4508
|
+
mkdirSync2(genDir, { recursive: true });
|
|
4509
|
+
writeFileSync3(join11(genDir, "gamedata.d.ts"), generateGamedataTypes(gamedata));
|
|
4232
4510
|
} else {
|
|
4233
|
-
rmSync2(
|
|
4511
|
+
rmSync2(join11(absDir, ".s2script", "gamedata.d.ts"), { force: true });
|
|
4234
4512
|
}
|
|
4235
4513
|
const declaredDepNames = [
|
|
4236
4514
|
...Object.keys(s2.pluginDependencies ?? {}),
|
|
@@ -4320,8 +4598,8 @@ ${lint.output}`);
|
|
|
4320
4598
|
`buildPlugin: no entry point found in ${pkgPath} (set s2script.main or main)`
|
|
4321
4599
|
);
|
|
4322
4600
|
}
|
|
4323
|
-
const entryPoint =
|
|
4324
|
-
const result = await
|
|
4601
|
+
const entryPoint = join11(absDir, entryRelative);
|
|
4602
|
+
const result = await esbuild2.build({
|
|
4325
4603
|
entryPoints: [entryPoint],
|
|
4326
4604
|
bundle: true,
|
|
4327
4605
|
platform: "neutral",
|
|
@@ -4332,7 +4610,15 @@ ${lint.output}`);
|
|
|
4332
4610
|
// declares `main` (rather than `exports`) fails to resolve with an undiagnosable error.
|
|
4333
4611
|
// Set it explicitly so a monorepo plugin bundles whichever field the author wrote.
|
|
4334
4612
|
mainFields: ["module", "main"],
|
|
4335
|
-
write: false
|
|
4613
|
+
write: false,
|
|
4614
|
+
// NODE_PATH semantics: `@edge/base64` resolves to .s2script/libs/@edge/base64 with no
|
|
4615
|
+
// per-package alias and no change to `external`. Libraries are BUNDLED IN by design.
|
|
4616
|
+
nodePaths: [librariesRoot(absDir)],
|
|
4617
|
+
// A WORKSPACE-sibling library (librariesResolved.siblingDirs) is not vendored under a
|
|
4618
|
+
// directory named for its package, so nodePaths alone cannot find it — alias each declared
|
|
4619
|
+
// name straight at the sibling's own directory instead, same "bundle the real source, no
|
|
4620
|
+
// copy" reasoning `resolveSiblingContracts` applies to contracts. Empty outside a workspace.
|
|
4621
|
+
alias: librariesResolved.siblingDirs
|
|
4336
4622
|
});
|
|
4337
4623
|
const pluginJs = result.outputFiles[0].text;
|
|
4338
4624
|
const manifest = {
|
|
@@ -4368,19 +4654,23 @@ ${lint.output}`);
|
|
|
4368
4654
|
};
|
|
4369
4655
|
if (gamedata) zipFiles["gamedata.json"] = Buffer.from(JSON.stringify(gamedata, null, 2));
|
|
4370
4656
|
if (gate.typesPath !== null && Object.keys(derivedPublishes).length > 0) {
|
|
4371
|
-
const contract =
|
|
4657
|
+
const contract = readFileSync8(gate.typesPath);
|
|
4372
4658
|
for (const iface of Object.keys(derivedPublishes)) {
|
|
4373
4659
|
const safe = iface.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
4374
4660
|
zipFiles[`types/${safe}.d.ts`] = contract;
|
|
4375
4661
|
}
|
|
4376
4662
|
}
|
|
4377
4663
|
const sanitizedId = name.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
4378
|
-
const outDir =
|
|
4379
|
-
|
|
4380
|
-
const outPath =
|
|
4381
|
-
|
|
4664
|
+
const outDir = join11(absDir, "dist");
|
|
4665
|
+
mkdirSync2(outDir, { recursive: true });
|
|
4666
|
+
const outPath = join11(outDir, `${sanitizedId}.s2sp`);
|
|
4667
|
+
writeFileSync3(outPath, zipSync(zipFiles));
|
|
4382
4668
|
return outPath;
|
|
4383
4669
|
}
|
|
4670
|
+
async function buildPackage(dir, packagesDir) {
|
|
4671
|
+
const pkg = JSON.parse(readFileSync8(join11(resolve10(dir), "package.json"), "utf8"));
|
|
4672
|
+
return packageKind(pkg) === "library" ? buildLibrary(dir, packagesDir) : buildPlugin(dir, packagesDir);
|
|
4673
|
+
}
|
|
4384
4674
|
|
|
4385
4675
|
// src/cli/args.ts
|
|
4386
4676
|
function parseFlag(args, name) {
|
|
@@ -4409,8 +4699,8 @@ function positionals(args, flagsWithValue) {
|
|
|
4409
4699
|
}
|
|
4410
4700
|
|
|
4411
4701
|
// src/workspace/build-all.ts
|
|
4412
|
-
import { writeFileSync as
|
|
4413
|
-
import { join as
|
|
4702
|
+
import { writeFileSync as writeFileSync4 } from "node:fs";
|
|
4703
|
+
import { join as join12 } from "node:path";
|
|
4414
4704
|
|
|
4415
4705
|
// src/workspace/graph.ts
|
|
4416
4706
|
function topoOrder(batch, warn = console.warn) {
|
|
@@ -4532,6 +4822,16 @@ function preflightWorkspace(ws) {
|
|
|
4532
4822
|
}
|
|
4533
4823
|
|
|
4534
4824
|
// src/workspace/build-all.ts
|
|
4825
|
+
function declaredLibraries(ws) {
|
|
4826
|
+
return ws.libs.filter((m) => packageKind(m.pkg) === "library");
|
|
4827
|
+
}
|
|
4828
|
+
function matchHits(pattern, members) {
|
|
4829
|
+
let hits = members.filter((m) => matchGlob(pattern, m.name));
|
|
4830
|
+
if (hits.length === 0 && pattern.includes("/")) {
|
|
4831
|
+
hits = members.filter((m) => matchGlob(pattern, m.relDir));
|
|
4832
|
+
}
|
|
4833
|
+
return hits;
|
|
4834
|
+
}
|
|
4535
4835
|
function collectFilters(argv2) {
|
|
4536
4836
|
const out = [];
|
|
4537
4837
|
for (let i2 = 0; i2 < argv2.length; i2++) {
|
|
@@ -4554,14 +4854,12 @@ function collectFilters(argv2) {
|
|
|
4554
4854
|
}
|
|
4555
4855
|
function selectPlugins(ws, filters) {
|
|
4556
4856
|
if (filters.length === 0) return ws.plugins;
|
|
4857
|
+
const libs = declaredLibraries(ws);
|
|
4557
4858
|
const chosen = /* @__PURE__ */ new Set();
|
|
4558
4859
|
const unmatched = [];
|
|
4559
4860
|
for (const pattern of filters) {
|
|
4560
|
-
|
|
4561
|
-
if (hits.length === 0 && pattern.
|
|
4562
|
-
hits = ws.plugins.filter((p) => matchGlob(pattern, p.relDir));
|
|
4563
|
-
}
|
|
4564
|
-
if (hits.length === 0) {
|
|
4861
|
+
const hits = matchHits(pattern, ws.plugins);
|
|
4862
|
+
if (hits.length === 0 && matchHits(pattern, libs).length === 0) {
|
|
4565
4863
|
unmatched.push(pattern);
|
|
4566
4864
|
continue;
|
|
4567
4865
|
}
|
|
@@ -4577,6 +4875,15 @@ function selectPlugins(ws, filters) {
|
|
|
4577
4875
|
}
|
|
4578
4876
|
return ws.plugins.filter((p) => chosen.has(p.name));
|
|
4579
4877
|
}
|
|
4878
|
+
function selectLibraries(ws, filters) {
|
|
4879
|
+
const libs = declaredLibraries(ws);
|
|
4880
|
+
if (filters.length === 0) return libs;
|
|
4881
|
+
const chosen = /* @__PURE__ */ new Set();
|
|
4882
|
+
for (const pattern of filters) {
|
|
4883
|
+
for (const m of matchHits(pattern, libs)) chosen.add(m.name);
|
|
4884
|
+
}
|
|
4885
|
+
return libs.filter((m) => chosen.has(m.name));
|
|
4886
|
+
}
|
|
4580
4887
|
function restampRange(range, version) {
|
|
4581
4888
|
const m = /^\s*(\^|~|>=|=)?\s*(\d+\.\d+\.\d+[0-9A-Za-z.+-]*)\s*$/.exec(range);
|
|
4582
4889
|
const rewritten = m ? `${m[1] ?? ""}${version}` : `^${version}`;
|
|
@@ -4614,7 +4921,7 @@ function stampWorkspaceVersion(ws, version) {
|
|
|
4614
4921
|
dirty = true;
|
|
4615
4922
|
}
|
|
4616
4923
|
}
|
|
4617
|
-
if (dirty)
|
|
4924
|
+
if (dirty) writeFileSync4(join12(p.dir, "package.json"), `${JSON.stringify(next, null, 2)}
|
|
4618
4925
|
`);
|
|
4619
4926
|
}
|
|
4620
4927
|
return result;
|
|
@@ -4643,16 +4950,30 @@ async function buildWorkspace(opts) {
|
|
|
4643
4950
|
);
|
|
4644
4951
|
}
|
|
4645
4952
|
const selected = selectPlugins(ws, opts.filters ?? []);
|
|
4953
|
+
const selectedLibraries = selectLibraries(ws, opts.filters ?? []);
|
|
4646
4954
|
preflightWorkspace(ws);
|
|
4647
4955
|
const ordered = orderPlugins(selected, warn);
|
|
4648
4956
|
opts.onPlan?.(ordered, stamp);
|
|
4649
4957
|
const outcomes = [];
|
|
4958
|
+
for (const lib of selectedLibraries) {
|
|
4959
|
+
const base = { name: lib.name, version: lib.version, relDir: lib.relDir };
|
|
4960
|
+
try {
|
|
4961
|
+
const outPath = await step(
|
|
4962
|
+
`Building ${lib.name}`,
|
|
4963
|
+
() => buildPackage(lib.dir, opts.packagesDir),
|
|
4964
|
+
(out) => `Built ${out}`
|
|
4965
|
+
);
|
|
4966
|
+
outcomes.push({ ...base, outPath });
|
|
4967
|
+
} catch (e) {
|
|
4968
|
+
outcomes.push({ ...base, error: e instanceof Error ? e.message : String(e) });
|
|
4969
|
+
}
|
|
4970
|
+
}
|
|
4650
4971
|
for (const p of ordered) {
|
|
4651
4972
|
const base = { name: p.name, version: p.version, relDir: p.relDir };
|
|
4652
4973
|
try {
|
|
4653
4974
|
const outPath = await step(
|
|
4654
4975
|
`Building ${p.name}`,
|
|
4655
|
-
() =>
|
|
4976
|
+
() => buildPackage(p.dir, opts.packagesDir),
|
|
4656
4977
|
(out) => `Built ${out}`
|
|
4657
4978
|
);
|
|
4658
4979
|
outcomes.push({ ...base, outPath });
|
|
@@ -5995,12 +6316,12 @@ async function run(argv2) {
|
|
|
5995
6316
|
const filters = collectFilters(argv2);
|
|
5996
6317
|
const stampVersion = parseFlag(argv2, "--stamp-version");
|
|
5997
6318
|
let dir = positionals(argv2, VALUE_FLAGS)[0];
|
|
5998
|
-
const wsRoot = findWorkspaceRoot(dir === void 0 ? process.cwd() :
|
|
5999
|
-
const workspaceMode = wsRoot !== null && (dir === void 0 ||
|
|
6319
|
+
const wsRoot = findWorkspaceRoot(dir === void 0 ? process.cwd() : resolve11(dir));
|
|
6320
|
+
const workspaceMode = wsRoot !== null && (dir === void 0 || resolve11(dir) === wsRoot);
|
|
6000
6321
|
if (!workspaceMode && (filters.length > 0 || stampVersion !== void 0)) {
|
|
6001
6322
|
const flag = filters.length > 0 ? "--filter" : "--stamp-version";
|
|
6002
6323
|
throw new Error(
|
|
6003
|
-
wsRoot === null ? `${flag} is a workspace flag, but no workspace root was found above ${dir === void 0 ? process.cwd() :
|
|
6324
|
+
wsRoot === null ? `${flag} is a workspace flag, but no workspace root was found above ${dir === void 0 ? process.cwd() : resolve11(dir)} \u2014 a workspace root is a package.json carrying an "s2script": { "workspace": { "plugins": [...] } } block` : `${flag} narrows a WORKSPACE build, but ${dir} names a single plugin \u2014 drop the argument (or pass ${wsRoot}) to build the workspace`
|
|
6004
6325
|
);
|
|
6005
6326
|
}
|
|
6006
6327
|
if (wsRoot !== null && workspaceMode) {
|
|
@@ -6018,10 +6339,10 @@ async function run(argv2) {
|
|
|
6018
6339
|
}
|
|
6019
6340
|
const packagesDir = resolvePackagesDir({
|
|
6020
6341
|
explicit: parseFlag(argv2, "--packages-dir"),
|
|
6021
|
-
pluginDir:
|
|
6342
|
+
pluginDir: resolve11(dir),
|
|
6022
6343
|
fromCliUrl: import.meta.url
|
|
6023
6344
|
});
|
|
6024
|
-
const out = await task(`Building ${dir}`, () =>
|
|
6345
|
+
const out = await task(`Building ${dir}`, () => buildPackage(dir, packagesDir), {
|
|
6025
6346
|
interactive,
|
|
6026
6347
|
done: (p) => `Built ${p}`
|
|
6027
6348
|
});
|
|
@@ -6078,14 +6399,14 @@ async function runWorkspace(argv2, root, interactive, filters, stampVersion) {
|
|
|
6078
6399
|
}
|
|
6079
6400
|
|
|
6080
6401
|
// src/commands/deploy.ts
|
|
6081
|
-
import { resolve as
|
|
6402
|
+
import { resolve as resolve13 } from "node:path";
|
|
6082
6403
|
|
|
6083
6404
|
// src/registry/deploy.ts
|
|
6084
|
-
import { readFileSync as
|
|
6085
|
-
import { resolve as
|
|
6405
|
+
import { readFileSync as readFileSync11 } from "node:fs";
|
|
6406
|
+
import { resolve as resolve12 } from "node:path";
|
|
6086
6407
|
|
|
6087
6408
|
// src/types-pack.ts
|
|
6088
|
-
import { readFileSync as
|
|
6409
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
6089
6410
|
import { gzipSync } from "node:zlib";
|
|
6090
6411
|
function pad(buf, size) {
|
|
6091
6412
|
if (buf.length > size) throw new Error(`tar field overflow (${buf.length}>${size})`);
|
|
@@ -6119,7 +6440,7 @@ function tarFile(name, content) {
|
|
|
6119
6440
|
return Buffer.concat([header, content, Buffer.alloc(padLen, 0)]);
|
|
6120
6441
|
}
|
|
6121
6442
|
function packTypesTarball(input) {
|
|
6122
|
-
const dts =
|
|
6443
|
+
const dts = readFileSync9(input.typesPath);
|
|
6123
6444
|
const pkgJson = Buffer.from(
|
|
6124
6445
|
JSON.stringify(
|
|
6125
6446
|
{
|
|
@@ -6146,11 +6467,11 @@ function packTypesTarball(input) {
|
|
|
6146
6467
|
}
|
|
6147
6468
|
|
|
6148
6469
|
// src/registry/credentials.ts
|
|
6149
|
-
import { existsSync as
|
|
6470
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync10, writeFileSync as writeFileSync5 } from "node:fs";
|
|
6150
6471
|
import { homedir } from "node:os";
|
|
6151
|
-
import { join as
|
|
6472
|
+
import { join as join13 } from "node:path";
|
|
6152
6473
|
function credentialsPath() {
|
|
6153
|
-
return
|
|
6474
|
+
return join13(homedir(), ".s2script", "credentials.json");
|
|
6154
6475
|
}
|
|
6155
6476
|
function normalizeRegistryUrl(url) {
|
|
6156
6477
|
const trimmed = url.replace(/\/$/, "");
|
|
@@ -6168,9 +6489,9 @@ function loadCredentials() {
|
|
|
6168
6489
|
return { registryUrl: defaultRegistryUrl(), token: fromEnv };
|
|
6169
6490
|
}
|
|
6170
6491
|
const p = credentialsPath();
|
|
6171
|
-
if (!
|
|
6492
|
+
if (!existsSync9(p)) return null;
|
|
6172
6493
|
try {
|
|
6173
|
-
const j = JSON.parse(
|
|
6494
|
+
const j = JSON.parse(readFileSync10(p, "utf8"));
|
|
6174
6495
|
if (!j.token) return null;
|
|
6175
6496
|
return {
|
|
6176
6497
|
registryUrl: normalizeRegistryUrl(j.registryUrl || defaultRegistryUrl()),
|
|
@@ -6181,9 +6502,9 @@ function loadCredentials() {
|
|
|
6181
6502
|
}
|
|
6182
6503
|
}
|
|
6183
6504
|
function saveCredentials(creds) {
|
|
6184
|
-
const dir =
|
|
6185
|
-
|
|
6186
|
-
|
|
6505
|
+
const dir = join13(homedir(), ".s2script");
|
|
6506
|
+
mkdirSync3(dir, { recursive: true });
|
|
6507
|
+
writeFileSync5(
|
|
6187
6508
|
credentialsPath(),
|
|
6188
6509
|
JSON.stringify(
|
|
6189
6510
|
{ registryUrl: normalizeRegistryUrl(creds.registryUrl), token: creds.token },
|
|
@@ -6213,7 +6534,8 @@ var TIMEOUTS_MS = {
|
|
|
6213
6534
|
meta: 3e4,
|
|
6214
6535
|
plan: 3e4,
|
|
6215
6536
|
"types download": 12e4,
|
|
6216
|
-
"s2sp download": 12e4
|
|
6537
|
+
"s2sp download": 12e4,
|
|
6538
|
+
"library download": 12e4
|
|
6217
6539
|
};
|
|
6218
6540
|
function rootCause(err2) {
|
|
6219
6541
|
let cur = err2;
|
|
@@ -6306,9 +6628,10 @@ var RegistryClient = class {
|
|
|
6306
6628
|
}
|
|
6307
6629
|
async deploy(opts) {
|
|
6308
6630
|
const entries = {
|
|
6309
|
-
"manifest.json": new TextEncoder().encode(JSON.stringify(opts.manifest))
|
|
6310
|
-
"plugin.s2sp": new Uint8Array(opts.s2sp)
|
|
6631
|
+
"manifest.json": new TextEncoder().encode(JSON.stringify(opts.manifest))
|
|
6311
6632
|
};
|
|
6633
|
+
if (opts.s2sp && opts.s2sp.length) entries["plugin.s2sp"] = new Uint8Array(opts.s2sp);
|
|
6634
|
+
if (opts.lib && opts.lib.length) entries["library.s2lib"] = new Uint8Array(opts.lib);
|
|
6312
6635
|
if (opts.types && opts.types.length) {
|
|
6313
6636
|
entries["types.tgz"] = new Uint8Array(opts.types);
|
|
6314
6637
|
}
|
|
@@ -6334,6 +6657,14 @@ var RegistryClient = class {
|
|
|
6334
6657
|
const res = await this.request("types download", u4);
|
|
6335
6658
|
return Buffer.from(await res.arrayBuffer());
|
|
6336
6659
|
}
|
|
6660
|
+
/** A library's own artifact — a .s2lib, never the plugin .s2sp shape. */
|
|
6661
|
+
async downloadLib(name, version) {
|
|
6662
|
+
const u4 = new URL(`${this.baseUrl}/api/v1/download/lib`);
|
|
6663
|
+
u4.searchParams.set("name", name);
|
|
6664
|
+
u4.searchParams.set("version", version);
|
|
6665
|
+
const res = await this.request("library download", u4);
|
|
6666
|
+
return Buffer.from(await res.arrayBuffer());
|
|
6667
|
+
}
|
|
6337
6668
|
async meta(name) {
|
|
6338
6669
|
const u4 = new URL(`${this.baseUrl}/api/v1/meta`);
|
|
6339
6670
|
u4.searchParams.set("name", name);
|
|
@@ -6365,10 +6696,19 @@ function assertDeployable(pkg, label) {
|
|
|
6365
6696
|
}
|
|
6366
6697
|
}
|
|
6367
6698
|
function assembleDeployArchive(pluginDir, pkg, outPath) {
|
|
6368
|
-
const absDir =
|
|
6699
|
+
const absDir = resolve12(pluginDir);
|
|
6700
|
+
if (packageKind(pkg) === "library") {
|
|
6701
|
+
const lib = readFileSync11(outPath);
|
|
6702
|
+
const manifestEntry2 = unzipSync(lib)["manifest.json"];
|
|
6703
|
+
if (!manifestEntry2) {
|
|
6704
|
+
throw new Error(`built archive missing manifest.json: ${outPath}`);
|
|
6705
|
+
}
|
|
6706
|
+
const manifest2 = JSON.parse(Buffer.from(manifestEntry2).toString("utf8"));
|
|
6707
|
+
return { manifest: manifest2, s2sp: null, lib, types: null };
|
|
6708
|
+
}
|
|
6369
6709
|
const gate = assertPublishesTypes(pkg, absDir);
|
|
6370
6710
|
if (!gate.ok) throw new Error(`publish gate failed: ${gate.error}`);
|
|
6371
|
-
const s2sp =
|
|
6711
|
+
const s2sp = readFileSync11(outPath);
|
|
6372
6712
|
const manifestEntry = unzipSync(s2sp)["manifest.json"];
|
|
6373
6713
|
if (!manifestEntry) {
|
|
6374
6714
|
throw new Error(`built archive missing manifest.json: ${outPath}`);
|
|
@@ -6383,11 +6723,11 @@ function assembleDeployArchive(pluginDir, pkg, outPath) {
|
|
|
6383
6723
|
publishes: hasPublishes(manifest.publishes) ? manifest.publishes : void 0
|
|
6384
6724
|
});
|
|
6385
6725
|
}
|
|
6386
|
-
return { manifest, s2sp, types };
|
|
6726
|
+
return { manifest, s2sp, lib: null, types };
|
|
6387
6727
|
}
|
|
6388
6728
|
async function deployPlugin(opts) {
|
|
6389
|
-
const absDir =
|
|
6390
|
-
const pkg = JSON.parse(
|
|
6729
|
+
const absDir = resolve12(opts.dir);
|
|
6730
|
+
const pkg = JSON.parse(readFileSync11(resolve12(absDir, "package.json"), "utf8"));
|
|
6391
6731
|
assertDeployable(pkg, absDir);
|
|
6392
6732
|
const creds = loadCredentials();
|
|
6393
6733
|
if (!creds?.token) {
|
|
@@ -6395,13 +6735,14 @@ async function deployPlugin(opts) {
|
|
|
6395
6735
|
opts.ci ? "S2SCRIPT_TOKEN required in CI" : "not logged in \u2014 run `s2s login` or set S2SCRIPT_TOKEN"
|
|
6396
6736
|
);
|
|
6397
6737
|
}
|
|
6398
|
-
const outPath = await buildPlugin(absDir, opts.packagesDir);
|
|
6399
|
-
const { manifest, s2sp, types } = assembleDeployArchive(absDir, pkg, outPath);
|
|
6738
|
+
const outPath = packageKind(pkg) === "library" ? await buildLibrary(absDir, opts.packagesDir) : await buildPlugin(absDir, opts.packagesDir);
|
|
6739
|
+
const { manifest, s2sp, lib, types } = assembleDeployArchive(absDir, pkg, outPath);
|
|
6400
6740
|
const client = new RegistryClient({
|
|
6401
6741
|
baseUrl: opts.registryUrl || creds.registryUrl || defaultRegistryUrl(),
|
|
6402
|
-
token: creds.token
|
|
6742
|
+
token: creds.token,
|
|
6743
|
+
fetch: opts.fetch
|
|
6403
6744
|
});
|
|
6404
|
-
return client.deploy({ manifest, s2sp, types });
|
|
6745
|
+
return client.deploy({ manifest, s2sp, lib, types });
|
|
6405
6746
|
}
|
|
6406
6747
|
|
|
6407
6748
|
// src/workspace/deploy-all.ts
|
|
@@ -6409,13 +6750,22 @@ function builtPluginsFromOutcomes(ws, outcomes) {
|
|
|
6409
6750
|
const byName = new Map(ws.plugins.map((p) => [p.name, p]));
|
|
6410
6751
|
const ordered = [];
|
|
6411
6752
|
const built = /* @__PURE__ */ new Map();
|
|
6753
|
+
const unpublishableLibraries = [];
|
|
6412
6754
|
for (const o of outcomes) {
|
|
6413
6755
|
const plugin = byName.get(o.name);
|
|
6414
|
-
if (!plugin)
|
|
6756
|
+
if (!plugin) {
|
|
6757
|
+
unpublishableLibraries.push(o);
|
|
6758
|
+
continue;
|
|
6759
|
+
}
|
|
6415
6760
|
ordered.push(plugin);
|
|
6416
6761
|
if (o.outPath !== void 0) built.set(o.name, { plugin, outPath: o.outPath });
|
|
6417
6762
|
}
|
|
6418
|
-
return { ordered, built };
|
|
6763
|
+
return { ordered, built, unpublishableLibraries };
|
|
6764
|
+
}
|
|
6765
|
+
function formatUnpublishableLibraries(outcomes) {
|
|
6766
|
+
return outcomes.map(
|
|
6767
|
+
(o) => ` skip ${o.name} (library outside s2script.workspace.plugins \u2014 publish with \`s2s deploy ${o.relDir}\`)`
|
|
6768
|
+
).join("\n");
|
|
6419
6769
|
}
|
|
6420
6770
|
async function isAlreadyPublished(client, name, version) {
|
|
6421
6771
|
try {
|
|
@@ -6497,9 +6847,9 @@ async function run2(argv2) {
|
|
|
6497
6847
|
"--stamp-version is a build-only flag (design spec 2026-07-27 \xA75.4) \u2014 s2s deploy never rewrites versions; run `s2s build --stamp-version <v>` first, then `s2s deploy`"
|
|
6498
6848
|
);
|
|
6499
6849
|
}
|
|
6500
|
-
const absDir =
|
|
6850
|
+
const absDir = resolve13(dir);
|
|
6501
6851
|
const root = findWorkspaceRoot(absDir);
|
|
6502
|
-
if (root !== null &&
|
|
6852
|
+
if (root !== null && resolve13(root) === absDir) {
|
|
6503
6853
|
await runWorkspaceDeploy({ root: absDir, argv: argv2, interactive, filters, dryRun, yes, ci });
|
|
6504
6854
|
return;
|
|
6505
6855
|
}
|
|
@@ -6560,7 +6910,7 @@ async function runWorkspaceDeploy(opts) {
|
|
|
6560
6910
|
console.log(out);
|
|
6561
6911
|
return out;
|
|
6562
6912
|
};
|
|
6563
|
-
const
|
|
6913
|
+
const build3 = await buildWorkspace({
|
|
6564
6914
|
workspace: ws,
|
|
6565
6915
|
packagesDir,
|
|
6566
6916
|
filters,
|
|
@@ -6570,13 +6920,16 @@ async function runWorkspaceDeploy(opts) {
|
|
|
6570
6920
|
label(`building ${plugins.length} plugin${plugins.length === 1 ? "" : "s"} (dependency order)`);
|
|
6571
6921
|
}
|
|
6572
6922
|
});
|
|
6573
|
-
if (
|
|
6574
|
-
throw new Error(formatBuildFailures(
|
|
6923
|
+
if (build3.failed.length > 0) {
|
|
6924
|
+
throw new Error(formatBuildFailures(build3.failed, build3.outcomes.length));
|
|
6575
6925
|
}
|
|
6576
|
-
const { ordered, built } = builtPluginsFromOutcomes(ws,
|
|
6926
|
+
const { ordered, built, unpublishableLibraries } = builtPluginsFromOutcomes(ws, build3.outcomes);
|
|
6577
6927
|
const plan = await computePlan(ordered, (name, version) => isAlreadyPublished(client, name, version));
|
|
6578
6928
|
label("plan:");
|
|
6579
6929
|
console.log(formatPlan(plan));
|
|
6930
|
+
if (unpublishableLibraries.length > 0) {
|
|
6931
|
+
console.log(formatUnpublishableLibraries(unpublishableLibraries));
|
|
6932
|
+
}
|
|
6580
6933
|
const toPublish = publishCount(plan);
|
|
6581
6934
|
if (toPublish === 0) {
|
|
6582
6935
|
label("nothing to publish");
|
|
@@ -6623,17 +6976,17 @@ async function runWorkspaceDeploy(opts) {
|
|
|
6623
6976
|
}
|
|
6624
6977
|
|
|
6625
6978
|
// src/commands/version.ts
|
|
6626
|
-
import { resolve as
|
|
6979
|
+
import { resolve as resolve14 } from "node:path";
|
|
6627
6980
|
|
|
6628
6981
|
// src/version/version.ts
|
|
6629
|
-
import { existsSync as
|
|
6630
|
-
import { join as
|
|
6982
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
6983
|
+
import { join as join16 } from "node:path";
|
|
6631
6984
|
|
|
6632
6985
|
// src/version/changesets.ts
|
|
6633
6986
|
var import_semver = __toESM(require_semver2(), 1);
|
|
6634
|
-
import { readFileSync as
|
|
6987
|
+
import { readFileSync as readFileSync12 } from "node:fs";
|
|
6635
6988
|
import { createRequire as createRequire2 } from "node:module";
|
|
6636
|
-
import { join as
|
|
6989
|
+
import { join as join14 } from "node:path";
|
|
6637
6990
|
import { pathToFileURL } from "node:url";
|
|
6638
6991
|
var SUPPORTED = {
|
|
6639
6992
|
"@changesets/assemble-release-plan": ">=6.0.0 <7.0.0",
|
|
@@ -6653,7 +7006,7 @@ function named(mod, key) {
|
|
|
6653
7006
|
return outer?.[key];
|
|
6654
7007
|
}
|
|
6655
7008
|
async function loadChangesets(workspaceRoot) {
|
|
6656
|
-
const require3 = createRequire2(
|
|
7009
|
+
const require3 = createRequire2(join14(workspaceRoot, "package.json"));
|
|
6657
7010
|
const missing = [];
|
|
6658
7011
|
const wrongVersion = [];
|
|
6659
7012
|
const resolved = /* @__PURE__ */ new Map();
|
|
@@ -6668,7 +7021,7 @@ async function loadChangesets(workspaceRoot) {
|
|
|
6668
7021
|
missing.push(name);
|
|
6669
7022
|
continue;
|
|
6670
7023
|
}
|
|
6671
|
-
const version = String(JSON.parse(
|
|
7024
|
+
const version = String(JSON.parse(readFileSync12(manifest, "utf8")).version ?? "");
|
|
6672
7025
|
if (!(0, import_semver.satisfies)(version, range, { includePrerelease: true })) {
|
|
6673
7026
|
wrongVersion.push(`${name}@${version} (supported: ${range})`);
|
|
6674
7027
|
continue;
|
|
@@ -6768,8 +7121,8 @@ function mirrorPackages(ws) {
|
|
|
6768
7121
|
|
|
6769
7122
|
// src/version/ranges.ts
|
|
6770
7123
|
var import_semver2 = __toESM(require_semver2(), 1);
|
|
6771
|
-
import { readFileSync as
|
|
6772
|
-
import { join as
|
|
7124
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync6 } from "node:fs";
|
|
7125
|
+
import { join as join15 } from "node:path";
|
|
6773
7126
|
var BUMP_LEVEL = { none: 0, patch: 1, minor: 2, major: 3 };
|
|
6774
7127
|
function rangePrefix(range) {
|
|
6775
7128
|
if (range.startsWith(">=")) return ">=";
|
|
@@ -6788,7 +7141,7 @@ function shouldUpdate(release, range, config) {
|
|
|
6788
7141
|
return BUMP_LEVEL[release.type] >= minLevel;
|
|
6789
7142
|
}
|
|
6790
7143
|
function readJsonFile(path) {
|
|
6791
|
-
const raw =
|
|
7144
|
+
const raw = readFileSync13(path, "utf8");
|
|
6792
7145
|
const match = /^[ \t]*[{[]\s*\n([ \t]+)/.exec(raw);
|
|
6793
7146
|
return {
|
|
6794
7147
|
json: JSON.parse(raw),
|
|
@@ -6829,12 +7182,12 @@ function rewriteSiblingRanges(ws, releases, config) {
|
|
|
6829
7182
|
for (const [consumerName, ifaceRanges] of edits) {
|
|
6830
7183
|
const plugin = ws.plugins.find((p) => p.name === consumerName);
|
|
6831
7184
|
if (plugin === void 0) continue;
|
|
6832
|
-
const path =
|
|
7185
|
+
const path = join15(plugin.dir, "package.json");
|
|
6833
7186
|
const { json, indent, eol } = readJsonFile(path);
|
|
6834
7187
|
const s2 = json.s2script;
|
|
6835
7188
|
if (s2?.pluginDependencies === void 0) continue;
|
|
6836
7189
|
for (const [iface, range] of ifaceRanges) s2.pluginDependencies[iface] = range;
|
|
6837
|
-
|
|
7190
|
+
writeFileSync6(path, JSON.stringify(json, null, indent) + eol);
|
|
6838
7191
|
touchedFiles.push(path);
|
|
6839
7192
|
}
|
|
6840
7193
|
return { rewrites, skips, touchedFiles };
|
|
@@ -6843,8 +7196,8 @@ function rewriteSiblingRanges(ws, releases, config) {
|
|
|
6843
7196
|
// src/version/version.ts
|
|
6844
7197
|
async function versionWorkspace(root, opts = {}) {
|
|
6845
7198
|
const ws = loadWorkspace(root);
|
|
6846
|
-
const configPath =
|
|
6847
|
-
if (!
|
|
7199
|
+
const configPath = join16(ws.root, ".changeset", "config.json");
|
|
7200
|
+
if (!existsSync10(configPath)) {
|
|
6848
7201
|
throw new Error(
|
|
6849
7202
|
`s2s version: ${configPath} does not exist \u2014 this workspace is not set up for changesets. Run \`npx changeset init\` at ${ws.root}.`
|
|
6850
7203
|
);
|
|
@@ -6882,7 +7235,7 @@ function resolveVersionRoot(from) {
|
|
|
6882
7235
|
async function run3(argv2) {
|
|
6883
7236
|
const interactive = isInteractive();
|
|
6884
7237
|
const [dirArg] = positionals(argv2, ["--since"]);
|
|
6885
|
-
const from =
|
|
7238
|
+
const from = resolve14(dirArg ?? ".");
|
|
6886
7239
|
try {
|
|
6887
7240
|
const root = resolveVersionRoot(from);
|
|
6888
7241
|
const result = await task(
|
|
@@ -6919,21 +7272,21 @@ async function run3(argv2) {
|
|
|
6919
7272
|
}
|
|
6920
7273
|
|
|
6921
7274
|
// src/commands/add.ts
|
|
6922
|
-
import { resolve as
|
|
7275
|
+
import { resolve as resolve16 } from "node:path";
|
|
6923
7276
|
|
|
6924
7277
|
// src/registry/add.ts
|
|
6925
7278
|
import {
|
|
6926
|
-
mkdirSync as
|
|
6927
|
-
writeFileSync as
|
|
6928
|
-
readFileSync as
|
|
6929
|
-
existsSync as
|
|
7279
|
+
mkdirSync as mkdirSync5,
|
|
7280
|
+
writeFileSync as writeFileSync9,
|
|
7281
|
+
readFileSync as readFileSync15,
|
|
7282
|
+
existsSync as existsSync12
|
|
6930
7283
|
} from "node:fs";
|
|
6931
|
-
import { join as
|
|
7284
|
+
import { join as join19, resolve as resolve15 } from "node:path";
|
|
6932
7285
|
import { gunzipSync } from "node:zlib";
|
|
6933
7286
|
|
|
6934
7287
|
// src/registry/npmrc.ts
|
|
6935
|
-
import { existsSync as
|
|
6936
|
-
import { join as
|
|
7288
|
+
import { existsSync as existsSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync7 } from "node:fs";
|
|
7289
|
+
import { join as join17 } from "node:path";
|
|
6937
7290
|
function npmCompatRegistryUrl(registryUrl) {
|
|
6938
7291
|
return `${registryUrl.replace(/\/$/, "")}/npm/`;
|
|
6939
7292
|
}
|
|
@@ -6949,8 +7302,8 @@ function ensureScopeNpmrc(projectDir, packageName, registryUrl) {
|
|
|
6949
7302
|
const compat = npmCompatRegistryUrl(registryUrl);
|
|
6950
7303
|
const key = `@${scope}:registry`;
|
|
6951
7304
|
const line = `${key}=${compat}`;
|
|
6952
|
-
const npmrcPath =
|
|
6953
|
-
let existing =
|
|
7305
|
+
const npmrcPath = join17(projectDir, ".npmrc");
|
|
7306
|
+
let existing = existsSync11(npmrcPath) ? readFileSync14(npmrcPath, "utf8") : "";
|
|
6954
7307
|
const lines = existing.split(/\r?\n/);
|
|
6955
7308
|
const idx = lines.findIndex((l2) => l2.trimStart().startsWith(`${key}=`) || l2.trimStart().startsWith(`${key} =`));
|
|
6956
7309
|
if (idx >= 0) {
|
|
@@ -6960,10 +7313,39 @@ function ensureScopeNpmrc(projectDir, packageName, registryUrl) {
|
|
|
6960
7313
|
lines.push(line);
|
|
6961
7314
|
}
|
|
6962
7315
|
const out = lines.filter((l2, i2, a2) => !(l2 === "" && a2[i2 - 1] === "")).join("\n");
|
|
6963
|
-
|
|
7316
|
+
writeFileSync7(npmrcPath, out.endsWith("\n") ? out : out + "\n");
|
|
6964
7317
|
return line;
|
|
6965
7318
|
}
|
|
6966
7319
|
|
|
7320
|
+
// src/registry/lib-extract.ts
|
|
7321
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync8 } from "node:fs";
|
|
7322
|
+
import { join as join18 } from "node:path";
|
|
7323
|
+
var WANTED = /* @__PURE__ */ new Set(["index.js", "index.d.ts"]);
|
|
7324
|
+
function extractLibArchive(s2lib, outDir, meta) {
|
|
7325
|
+
const entries = unzipSync(new Uint8Array(s2lib));
|
|
7326
|
+
if (!entries["index.js"]?.length) throw new Error("library archive missing index.js");
|
|
7327
|
+
if (!entries["index.d.ts"]?.length) throw new Error("library archive missing index.d.ts");
|
|
7328
|
+
mkdirSync4(outDir, { recursive: true });
|
|
7329
|
+
for (const [name, bytes] of Object.entries(entries)) {
|
|
7330
|
+
if (!WANTED.has(name)) continue;
|
|
7331
|
+
writeFileSync8(join18(outDir, name), Buffer.from(bytes));
|
|
7332
|
+
}
|
|
7333
|
+
let apiVersion = "1.x";
|
|
7334
|
+
try {
|
|
7335
|
+
const m = JSON.parse(Buffer.from(entries["manifest.json"] ?? new Uint8Array()).toString("utf8"));
|
|
7336
|
+
if (typeof m.apiVersion === "string") apiVersion = m.apiVersion;
|
|
7337
|
+
} catch {
|
|
7338
|
+
}
|
|
7339
|
+
writeFileSync8(
|
|
7340
|
+
join18(outDir, "package.json"),
|
|
7341
|
+
JSON.stringify(
|
|
7342
|
+
{ name: meta.name, version: meta.version, main: "index.js", types: "index.d.ts", s2script: { kind: "library", apiVersion } },
|
|
7343
|
+
null,
|
|
7344
|
+
2
|
|
7345
|
+
) + "\n"
|
|
7346
|
+
);
|
|
7347
|
+
}
|
|
7348
|
+
|
|
6967
7349
|
// src/registry/add.ts
|
|
6968
7350
|
function parseSpec(spec) {
|
|
6969
7351
|
if (spec.startsWith("@")) {
|
|
@@ -6977,7 +7359,7 @@ function parseSpec(spec) {
|
|
|
6977
7359
|
}
|
|
6978
7360
|
function extractTypesTarball(tgz, outDir) {
|
|
6979
7361
|
const tar = gunzipSync(tgz);
|
|
6980
|
-
|
|
7362
|
+
mkdirSync5(outDir, { recursive: true });
|
|
6981
7363
|
let offset = 0;
|
|
6982
7364
|
let wroteContract = false;
|
|
6983
7365
|
while (offset + 512 <= tar.length) {
|
|
@@ -6992,45 +7374,73 @@ function extractTypesTarball(tgz, outDir) {
|
|
|
6992
7374
|
if (!name || name.endsWith("/")) continue;
|
|
6993
7375
|
const base = name.replace(/^package\//, "");
|
|
6994
7376
|
if (base === "package.json") {
|
|
6995
|
-
|
|
7377
|
+
writeFileSync9(join19(outDir, "package.json"), content);
|
|
6996
7378
|
} else if (base === "api.d.ts" || base === "index.d.ts") {
|
|
6997
|
-
|
|
7379
|
+
writeFileSync9(join19(outDir, "index.d.ts"), content);
|
|
6998
7380
|
wroteContract = true;
|
|
6999
7381
|
}
|
|
7000
7382
|
}
|
|
7001
|
-
if (!wroteContract && !
|
|
7383
|
+
if (!wroteContract && !existsSync12(join19(outDir, "index.d.ts"))) {
|
|
7002
7384
|
throw new Error("types tarball missing package/api.d.ts (or index.d.ts)");
|
|
7003
7385
|
}
|
|
7004
7386
|
}
|
|
7387
|
+
function rangeForResolved(range, version) {
|
|
7388
|
+
const major2 = version.split(".")[0] ?? "0";
|
|
7389
|
+
return range.startsWith("^") || range === "*" ? `^${major2}.0.0` : range.includes(".") ? range : `^${version}`;
|
|
7390
|
+
}
|
|
7005
7391
|
async function addPackage(opts) {
|
|
7006
|
-
const absDir =
|
|
7392
|
+
const absDir = resolve15(opts.pluginDir);
|
|
7007
7393
|
const { name, range } = parseSpec(opts.spec);
|
|
7008
7394
|
const creds = loadCredentials();
|
|
7009
7395
|
const client = new RegistryClient({
|
|
7010
7396
|
baseUrl: opts.registryUrl || creds?.registryUrl || defaultRegistryUrl(),
|
|
7011
|
-
token: creds?.token
|
|
7397
|
+
token: creds?.token,
|
|
7398
|
+
fetch: opts.fetch
|
|
7012
7399
|
});
|
|
7013
7400
|
const resolved = await client.resolve(name, range);
|
|
7401
|
+
if (resolved.kind === "library") {
|
|
7402
|
+
const s2lib = await client.downloadLib(name, resolved.version);
|
|
7403
|
+
const libDir = join19(absDir, ".s2script", "libs", ...name.split("/"));
|
|
7404
|
+
extractLibArchive(s2lib, libDir, { name, version: resolved.version });
|
|
7405
|
+
const pkgPath2 = join19(absDir, "package.json");
|
|
7406
|
+
const pkg2 = JSON.parse(readFileSync15(pkgPath2, "utf8"));
|
|
7407
|
+
pkg2.s2script = pkg2.s2script ?? {};
|
|
7408
|
+
pkg2.s2script.libraries = pkg2.s2script.libraries ?? {};
|
|
7409
|
+
pkg2.s2script.libraries[name] = rangeForResolved(range, resolved.version);
|
|
7410
|
+
writeFileSync9(pkgPath2, JSON.stringify(pkg2, null, 2) + "\n");
|
|
7411
|
+
return {
|
|
7412
|
+
kind: "library",
|
|
7413
|
+
name: resolved.name,
|
|
7414
|
+
version: resolved.version,
|
|
7415
|
+
reviewState: resolved.reviewState,
|
|
7416
|
+
typesDir: null,
|
|
7417
|
+
libDir,
|
|
7418
|
+
// Deliberately NO .npmrc line: nothing about a library may look like an npm
|
|
7419
|
+
// package — that is the exact confusion this feature exists to prevent.
|
|
7420
|
+
npmrcLine: null
|
|
7421
|
+
};
|
|
7422
|
+
}
|
|
7014
7423
|
if (!resolved.hasTypes) {
|
|
7015
7424
|
throw new Error(`${name}@${resolved.version} has no types artifact (runtime-only package?)`);
|
|
7016
7425
|
}
|
|
7017
7426
|
const tgz = await client.downloadTypes(name, resolved.version);
|
|
7018
|
-
const typesDir =
|
|
7427
|
+
const typesDir = join19(absDir, ".s2script", "types", ...name.split("/"));
|
|
7019
7428
|
extractTypesTarball(tgz, typesDir);
|
|
7020
|
-
const pkgPath =
|
|
7021
|
-
const pkg = JSON.parse(
|
|
7429
|
+
const pkgPath = join19(absDir, "package.json");
|
|
7430
|
+
const pkg = JSON.parse(readFileSync15(pkgPath, "utf8"));
|
|
7022
7431
|
pkg.s2script = pkg.s2script ?? {};
|
|
7023
7432
|
pkg.s2script.pluginDependencies = pkg.s2script.pluginDependencies ?? {};
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
writeFileSync7(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
7433
|
+
pkg.s2script.pluginDependencies[name] = rangeForResolved(range, resolved.version);
|
|
7434
|
+
writeFileSync9(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
7027
7435
|
const registryUrl = opts.registryUrl || creds?.registryUrl || defaultRegistryUrl();
|
|
7028
7436
|
const npmrcLine = ensureScopeNpmrc(absDir, name, registryUrl);
|
|
7029
7437
|
return {
|
|
7438
|
+
kind: "plugin",
|
|
7030
7439
|
name: resolved.name,
|
|
7031
7440
|
version: resolved.version,
|
|
7032
7441
|
reviewState: resolved.reviewState,
|
|
7033
7442
|
typesDir,
|
|
7443
|
+
libDir: null,
|
|
7034
7444
|
npmrcLine
|
|
7035
7445
|
};
|
|
7036
7446
|
}
|
|
@@ -7049,9 +7459,9 @@ async function run4(argv2) {
|
|
|
7049
7459
|
}
|
|
7050
7460
|
try {
|
|
7051
7461
|
const pluginDir = parseFlag(argv2, "--dir") || ".";
|
|
7052
|
-
const absDir =
|
|
7462
|
+
const absDir = resolve16(pluginDir);
|
|
7053
7463
|
const root = findWorkspaceRoot(absDir);
|
|
7054
|
-
if (root !== null &&
|
|
7464
|
+
if (root !== null && resolve16(root) === absDir) {
|
|
7055
7465
|
throw new Error(
|
|
7056
7466
|
`${absDir} is a workspace root (design spec 2026-07-27 \xA74.1), not a plugin \u2014 \`s2s add\` needs a plugin directory: pass --dir <plugin> (e.g. --dir plugins/shop)`
|
|
7057
7467
|
);
|
|
@@ -7063,14 +7473,24 @@ async function run4(argv2) {
|
|
|
7063
7473
|
spec,
|
|
7064
7474
|
registryUrl: parseFlag(argv2, "--registry")
|
|
7065
7475
|
}),
|
|
7066
|
-
{
|
|
7476
|
+
{
|
|
7477
|
+
interactive,
|
|
7478
|
+
done: (r2) => r2.kind === "library" ? `Added library ${r2.name}@${r2.version} \u2192 ${r2.libDir} (commit this directory)` : `Added ${r2.name}@${r2.version} \u2192 ${r2.typesDir}`
|
|
7479
|
+
}
|
|
7067
7480
|
);
|
|
7068
7481
|
if (interactive) {
|
|
7069
7482
|
if (result.npmrcLine) {
|
|
7070
7483
|
log2.info(`npmrc: ${result.npmrcLine} (types-only; npm install ${result.name} also works)`);
|
|
7071
7484
|
}
|
|
7072
7485
|
if (result.reviewState === "unreviewed") {
|
|
7073
|
-
log2.warn(
|
|
7486
|
+
log2.warn(
|
|
7487
|
+
result.kind === "library" ? "Not reviewed by s2script \u2014 library pulled; use at your own risk." : "Not reviewed by s2script \u2014 types pulled; use at your own risk."
|
|
7488
|
+
);
|
|
7489
|
+
}
|
|
7490
|
+
} else if (result.kind === "library") {
|
|
7491
|
+
console.log(`added library ${result.name}@${result.version} \u2192 ${result.libDir}`);
|
|
7492
|
+
if (result.reviewState === "unreviewed") {
|
|
7493
|
+
console.log("note: Not reviewed by s2script \u2014 library pulled; use at your own risk.");
|
|
7074
7494
|
}
|
|
7075
7495
|
} else {
|
|
7076
7496
|
console.log(`added ${result.name}@${result.version} \u2192 ${result.typesDir}`);
|
|
@@ -7088,13 +7508,13 @@ async function run4(argv2) {
|
|
|
7088
7508
|
}
|
|
7089
7509
|
|
|
7090
7510
|
// src/commands/install.ts
|
|
7091
|
-
import { resolve as
|
|
7092
|
-
import { existsSync as
|
|
7511
|
+
import { resolve as resolve18 } from "node:path";
|
|
7512
|
+
import { existsSync as existsSync14 } from "node:fs";
|
|
7093
7513
|
|
|
7094
7514
|
// src/registry/install.ts
|
|
7095
7515
|
import { createHash as createHash2 } from "node:crypto";
|
|
7096
|
-
import { mkdirSync as
|
|
7097
|
-
import { basename as basename2, join as
|
|
7516
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync16, writeFileSync as writeFileSync10, renameSync, existsSync as existsSync13 } from "node:fs";
|
|
7517
|
+
import { basename as basename2, join as join20, resolve as resolve17, sep as sep3 } from "node:path";
|
|
7098
7518
|
function parseManifest(input) {
|
|
7099
7519
|
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
7100
7520
|
throw new Error("manifest must be a JSON object");
|
|
@@ -7177,14 +7597,14 @@ async function installPlan(opts) {
|
|
|
7177
7597
|
);
|
|
7178
7598
|
}
|
|
7179
7599
|
}
|
|
7180
|
-
const dirResolved =
|
|
7600
|
+
const dirResolved = resolve17(opts.dir);
|
|
7181
7601
|
const targets = install.map((e) => {
|
|
7182
7602
|
if (!e.sha256) {
|
|
7183
7603
|
throw new Error(`refusing ${e.name}@${e.version}: registry did not provide a sha256 to verify against`);
|
|
7184
7604
|
}
|
|
7185
7605
|
const filename = safeFilename(e);
|
|
7186
|
-
const dest =
|
|
7187
|
-
if (dest !== dirResolved && !dest.startsWith(dirResolved +
|
|
7606
|
+
const dest = resolve17(join20(opts.dir, filename));
|
|
7607
|
+
if (dest !== dirResolved && !dest.startsWith(dirResolved + sep3)) {
|
|
7188
7608
|
throw new Error(`refusing ${e.name}@${e.version}: destination "${dest}" escapes plugins dir "${dirResolved}"`);
|
|
7189
7609
|
}
|
|
7190
7610
|
return { entry: e, filename, dest };
|
|
@@ -7194,12 +7614,12 @@ async function installPlan(opts) {
|
|
|
7194
7614
|
for (const e of install) log3(`would install ${e.name}@${e.version} -> ${e.filename}`);
|
|
7195
7615
|
return { written: [], skipped: [], warnings };
|
|
7196
7616
|
}
|
|
7197
|
-
|
|
7617
|
+
mkdirSync6(opts.dir, { recursive: true });
|
|
7198
7618
|
const written = [];
|
|
7199
7619
|
const skipped = [];
|
|
7200
7620
|
for (const { entry: e, filename, dest } of targets) {
|
|
7201
|
-
if (
|
|
7202
|
-
const have = sha256Hex(
|
|
7621
|
+
if (existsSync13(dest)) {
|
|
7622
|
+
const have = sha256Hex(readFileSync16(dest));
|
|
7203
7623
|
if (have === e.sha256) {
|
|
7204
7624
|
skipped.push(filename);
|
|
7205
7625
|
log3(`up to date ${filename}`);
|
|
@@ -7212,7 +7632,7 @@ async function installPlan(opts) {
|
|
|
7212
7632
|
throw new Error(`sha256 mismatch for ${e.name}@${e.version}: expected ${e.sha256}, got ${got}`);
|
|
7213
7633
|
}
|
|
7214
7634
|
const tmp = `${dest}.${process.pid}.tmp`;
|
|
7215
|
-
|
|
7635
|
+
writeFileSync10(tmp, bytes);
|
|
7216
7636
|
renameSync(tmp, dest);
|
|
7217
7637
|
written.push(filename);
|
|
7218
7638
|
log3(`installed ${e.name}@${e.version} -> ${filename}`);
|
|
@@ -7220,8 +7640,8 @@ async function installPlan(opts) {
|
|
|
7220
7640
|
return { written, skipped, warnings };
|
|
7221
7641
|
}
|
|
7222
7642
|
function loadManifestFile(path) {
|
|
7223
|
-
if (!
|
|
7224
|
-
return parseManifest(JSON.parse(
|
|
7643
|
+
if (!existsSync13(path)) return { plugins: {} };
|
|
7644
|
+
return parseManifest(JSON.parse(readFileSync16(path, "utf8")));
|
|
7225
7645
|
}
|
|
7226
7646
|
|
|
7227
7647
|
// src/commands/install.ts
|
|
@@ -7234,7 +7654,7 @@ async function run5(argv2) {
|
|
|
7234
7654
|
const reviewedOnly = hasFlag(argv2, "--reviewed-only");
|
|
7235
7655
|
let dir = parseFlag(argv2, "--dir");
|
|
7236
7656
|
if (!dir) {
|
|
7237
|
-
if (
|
|
7657
|
+
if (existsSync14(resolve18(AUTODETECT))) dir = resolve18(AUTODETECT);
|
|
7238
7658
|
else {
|
|
7239
7659
|
console.error(
|
|
7240
7660
|
`Usage: s2s install [name[@range]...] --dir <plugins dir>
|
|
@@ -7245,7 +7665,7 @@ async function run5(argv2) {
|
|
|
7245
7665
|
}
|
|
7246
7666
|
const client = new RegistryClient({ baseUrl: registry });
|
|
7247
7667
|
try {
|
|
7248
|
-
const manifest = loadManifestFile(
|
|
7668
|
+
const manifest = loadManifestFile(resolve18(file));
|
|
7249
7669
|
const specs = mergeSpecs(manifest, args);
|
|
7250
7670
|
if (Object.keys(specs).length === 0) {
|
|
7251
7671
|
console.error(
|
|
@@ -7275,32 +7695,32 @@ async function run5(argv2) {
|
|
|
7275
7695
|
}
|
|
7276
7696
|
|
|
7277
7697
|
// src/commands/create.ts
|
|
7278
|
-
import { resolve as
|
|
7698
|
+
import { resolve as resolve21 } from "node:path";
|
|
7279
7699
|
|
|
7280
7700
|
// src/create/create.ts
|
|
7281
7701
|
import {
|
|
7282
|
-
mkdirSync as
|
|
7283
|
-
writeFileSync as
|
|
7284
|
-
existsSync as
|
|
7702
|
+
mkdirSync as mkdirSync7,
|
|
7703
|
+
writeFileSync as writeFileSync11,
|
|
7704
|
+
existsSync as existsSync15,
|
|
7285
7705
|
readdirSync as readdirSync4,
|
|
7286
|
-
readFileSync as
|
|
7706
|
+
readFileSync as readFileSync17,
|
|
7287
7707
|
symlinkSync
|
|
7288
7708
|
} from "node:fs";
|
|
7289
|
-
import { dirname as
|
|
7709
|
+
import { dirname as dirname5, isAbsolute, join as join21, relative as relative2, resolve as resolve19, basename as basename3 } from "node:path";
|
|
7290
7710
|
import { spawnSync } from "node:child_process";
|
|
7291
7711
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
7292
7712
|
function readCliVersion() {
|
|
7293
|
-
const here =
|
|
7713
|
+
const here = dirname5(fileURLToPath2(import.meta.url));
|
|
7294
7714
|
const candidates = [
|
|
7295
|
-
|
|
7715
|
+
join21(here, "..", "package.json"),
|
|
7296
7716
|
// dist/cli.js → packages/sdk/package.json
|
|
7297
|
-
|
|
7717
|
+
join21(here, "..", "..", "package.json")
|
|
7298
7718
|
// src/create → packages/sdk/package.json
|
|
7299
7719
|
];
|
|
7300
7720
|
for (const p of candidates) {
|
|
7301
|
-
if (!
|
|
7721
|
+
if (!existsSync15(p)) continue;
|
|
7302
7722
|
try {
|
|
7303
|
-
const pkg = JSON.parse(
|
|
7723
|
+
const pkg = JSON.parse(readFileSync17(p, "utf8"));
|
|
7304
7724
|
if (pkg.name === "@s2script/sdk" && pkg.version) return pkg.version;
|
|
7305
7725
|
} catch {
|
|
7306
7726
|
}
|
|
@@ -7308,27 +7728,27 @@ function readCliVersion() {
|
|
|
7308
7728
|
return "0.1.0";
|
|
7309
7729
|
}
|
|
7310
7730
|
function findLocalPackagesDir() {
|
|
7311
|
-
const here =
|
|
7731
|
+
const here = dirname5(fileURLToPath2(import.meta.url));
|
|
7312
7732
|
const candidates = [
|
|
7313
|
-
|
|
7733
|
+
join21(here, "..", ".."),
|
|
7314
7734
|
// dist/cli.js → packages
|
|
7315
|
-
|
|
7735
|
+
join21(here, "..", "..", "..")
|
|
7316
7736
|
// src/create → packages
|
|
7317
7737
|
];
|
|
7318
7738
|
for (const c2 of candidates) {
|
|
7319
|
-
if (isPackagesDir(c2)) return
|
|
7739
|
+
if (isPackagesDir(c2)) return resolve19(c2);
|
|
7320
7740
|
}
|
|
7321
7741
|
return void 0;
|
|
7322
7742
|
}
|
|
7323
7743
|
function slugifyBasename(dir, fallback = "plugin") {
|
|
7324
|
-
const base = basename3(
|
|
7744
|
+
const base = basename3(resolve19(dir));
|
|
7325
7745
|
return base.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase() || fallback;
|
|
7326
7746
|
}
|
|
7327
|
-
function defaultNameFromPath(dir) {
|
|
7328
|
-
return
|
|
7747
|
+
function defaultNameFromPath(dir, kind = "plugin") {
|
|
7748
|
+
return `@${kind}/${slugifyBasename(dir)}`;
|
|
7329
7749
|
}
|
|
7330
7750
|
function assertEmptyTarget(targetPath) {
|
|
7331
|
-
if (!
|
|
7751
|
+
if (!existsSync15(targetPath)) return;
|
|
7332
7752
|
const kids = readdirSync4(targetPath);
|
|
7333
7753
|
const meaningful = kids.filter((k) => k !== ".git");
|
|
7334
7754
|
if (meaningful.length) {
|
|
@@ -7367,18 +7787,18 @@ function versionSpecFrom(status, stdout2) {
|
|
|
7367
7787
|
const v = (stdout2 ?? "").trim();
|
|
7368
7788
|
return status === 0 && /^\d+\.\d+\.\d+/.test(v) ? `^${v}` : "latest";
|
|
7369
7789
|
}
|
|
7370
|
-
function registryDevDeps(game, sdkVersion,
|
|
7790
|
+
function registryDevDeps(game, sdkVersion, resolve22 = resolvePublishedVersion) {
|
|
7371
7791
|
const deps = {};
|
|
7372
7792
|
for (const n3 of createPackageNames(game)) {
|
|
7373
|
-
deps[`@s2script/${n3}`] = n3 === "sdk" ? `^${sdkVersion}` :
|
|
7793
|
+
deps[`@s2script/${n3}`] = n3 === "sdk" ? `^${sdkVersion}` : resolve22(`@s2script/${n3}`);
|
|
7374
7794
|
}
|
|
7375
7795
|
return deps;
|
|
7376
7796
|
}
|
|
7377
7797
|
function fileDevDeps(packagesDir, game) {
|
|
7378
7798
|
const deps = {};
|
|
7379
7799
|
for (const n3 of createPackageNames(game)) {
|
|
7380
|
-
const abs =
|
|
7381
|
-
if (!
|
|
7800
|
+
const abs = join21(packagesDir, n3);
|
|
7801
|
+
if (!existsSync15(join21(abs, "package.json"))) return void 0;
|
|
7382
7802
|
deps[`@s2script/${n3}`] = `file:${abs}`;
|
|
7383
7803
|
}
|
|
7384
7804
|
return deps;
|
|
@@ -7410,6 +7830,13 @@ export default plugin((ctx) => {
|
|
|
7410
7830
|
});
|
|
7411
7831
|
`;
|
|
7412
7832
|
}
|
|
7833
|
+
var LIBRARY_ENTRY = `/** Encode a string. Replace this with the library's real surface. */
|
|
7834
|
+
export function encode(input: string): string {
|
|
7835
|
+
return input;
|
|
7836
|
+
}
|
|
7837
|
+
`;
|
|
7838
|
+
var LIBRARY_TYPES = `export declare function encode(input: string): string;
|
|
7839
|
+
`;
|
|
7413
7840
|
var ESLINT_RANGE = "^10.7.0";
|
|
7414
7841
|
function eslintConfig() {
|
|
7415
7842
|
return `import s2script from "@s2script/eslint-plugin";
|
|
@@ -7435,7 +7862,7 @@ function tsconfigJson() {
|
|
|
7435
7862
|
) + "\n";
|
|
7436
7863
|
}
|
|
7437
7864
|
function workspaceTsconfigJson(targetPath, workspaceRoot) {
|
|
7438
|
-
const rel = relative2(targetPath,
|
|
7865
|
+
const rel = relative2(targetPath, join21(workspaceRoot, "tsconfig.base.json")).replace(/\\/g, "/");
|
|
7439
7866
|
return JSON.stringify(
|
|
7440
7867
|
{
|
|
7441
7868
|
extends: rel.startsWith(".") ? rel : `./${rel}`,
|
|
@@ -7481,6 +7908,28 @@ function packageJsonContent(name, game, version, localPackagesDir) {
|
|
|
7481
7908
|
2
|
|
7482
7909
|
) + "\n";
|
|
7483
7910
|
}
|
|
7911
|
+
function libraryPackageJsonContent(name, game, version, localPackagesDir) {
|
|
7912
|
+
const fileDeps = localPackagesDir ? fileDevDeps(localPackagesDir, game) : void 0;
|
|
7913
|
+
const devDependencies = {
|
|
7914
|
+
...fileDeps ?? registryDevDeps(game, version),
|
|
7915
|
+
eslint: ESLINT_RANGE
|
|
7916
|
+
};
|
|
7917
|
+
return JSON.stringify(
|
|
7918
|
+
{
|
|
7919
|
+
name,
|
|
7920
|
+
version: "0.1.0",
|
|
7921
|
+
main: "src/index.ts",
|
|
7922
|
+
types: "src/index.d.ts",
|
|
7923
|
+
scripts: {
|
|
7924
|
+
build: "s2s build ."
|
|
7925
|
+
},
|
|
7926
|
+
s2script: { kind: "library" },
|
|
7927
|
+
devDependencies
|
|
7928
|
+
},
|
|
7929
|
+
null,
|
|
7930
|
+
2
|
|
7931
|
+
) + "\n";
|
|
7932
|
+
}
|
|
7484
7933
|
function gitignore() {
|
|
7485
7934
|
return `node_modules/
|
|
7486
7935
|
dist/
|
|
@@ -7489,10 +7938,10 @@ dist/
|
|
|
7489
7938
|
`;
|
|
7490
7939
|
}
|
|
7491
7940
|
function linkLocalPackagesForNoInstall(targetPath, localPackagesDir) {
|
|
7492
|
-
const nm =
|
|
7493
|
-
|
|
7494
|
-
const dest =
|
|
7495
|
-
if (!
|
|
7941
|
+
const nm = join21(targetPath, "node_modules");
|
|
7942
|
+
mkdirSync7(nm, { recursive: true });
|
|
7943
|
+
const dest = join21(nm, "@s2script");
|
|
7944
|
+
if (!existsSync15(dest)) symlinkSync(localPackagesDir, dest);
|
|
7496
7945
|
}
|
|
7497
7946
|
function runInstall(dir, pm) {
|
|
7498
7947
|
if (pm === "none") return;
|
|
@@ -7508,14 +7957,20 @@ async function createPlugin(opts = {}) {
|
|
|
7508
7957
|
const interactive = isInteractive({ yes: opts.yes });
|
|
7509
7958
|
let game = assertGame(opts.game);
|
|
7510
7959
|
let name = opts.name;
|
|
7960
|
+
let kind = opts.kind ?? "plugin";
|
|
7511
7961
|
let install = opts.noInstall ? "none" : assertInstall(opts.install);
|
|
7512
7962
|
const template = opts.template ?? "minimal";
|
|
7513
7963
|
if (template !== "minimal") {
|
|
7514
7964
|
throw new Error(`unknown template ${JSON.stringify(template)} (v1 supports: minimal)`);
|
|
7515
7965
|
}
|
|
7516
7966
|
const workspaceRoot = opts.workspaceRoot;
|
|
7967
|
+
if (kind === "library" && workspaceRoot !== void 0) {
|
|
7968
|
+
throw new Error(
|
|
7969
|
+
`s2s create --library does not support workspace mode yet (workspace detected at ${workspaceRoot}) \u2014 a workspace library needs to sit outside the plugins/ glob (e.g. a sibling directory like libs/<name>, matched by npm's own "workspaces" field but not by s2script.workspace.plugins \u2014 see examples/workspace-library for a worked one); add it by hand for now`
|
|
7970
|
+
);
|
|
7971
|
+
}
|
|
7517
7972
|
let slug = workspaceRoot !== void 0 && opts.path !== void 0 ? assertBareSlug(opts.path) : opts.path;
|
|
7518
|
-
let targetPath = workspaceRoot === void 0 ?
|
|
7973
|
+
let targetPath = workspaceRoot === void 0 ? resolve19(opts.path ?? ".") : slug === void 0 ? void 0 : join21(workspaceRoot, "plugins", slug);
|
|
7519
7974
|
if (targetPath !== void 0) assertEmptyTarget(targetPath);
|
|
7520
7975
|
if (interactive) {
|
|
7521
7976
|
intro2("Create an s2script plugin");
|
|
@@ -7525,10 +7980,20 @@ async function createPlugin(opts = {}) {
|
|
|
7525
7980
|
slug = assertBareSlug(
|
|
7526
7981
|
await text2({ message: "Plugin name (directory under plugins/)", placeholder: "myplugin" })
|
|
7527
7982
|
);
|
|
7528
|
-
targetPath =
|
|
7983
|
+
targetPath = join21(workspaceRoot, "plugins", slug);
|
|
7529
7984
|
assertEmptyTarget(targetPath);
|
|
7530
7985
|
}
|
|
7531
7986
|
}
|
|
7987
|
+
if (opts.kind === void 0 && workspaceRoot === void 0) {
|
|
7988
|
+
kind = await select2({
|
|
7989
|
+
message: "What are you creating?",
|
|
7990
|
+
options: [
|
|
7991
|
+
{ value: "plugin", label: "Plugin \u2014 loads on a server" },
|
|
7992
|
+
{ value: "library", label: "Library \u2014 build-time code other plugins bundle" }
|
|
7993
|
+
],
|
|
7994
|
+
initialValue: "plugin"
|
|
7995
|
+
});
|
|
7996
|
+
}
|
|
7532
7997
|
if (!game) {
|
|
7533
7998
|
game = await select2({
|
|
7534
7999
|
message: "Which game?",
|
|
@@ -7542,9 +8007,9 @@ async function createPlugin(opts = {}) {
|
|
|
7542
8007
|
if (!name) {
|
|
7543
8008
|
const known = targetPath;
|
|
7544
8009
|
name = await text2({
|
|
7545
|
-
message: "Plugin package name",
|
|
7546
|
-
defaultValue: defaultNameFromPath(known),
|
|
7547
|
-
placeholder: defaultNameFromPath(known)
|
|
8010
|
+
message: kind === "library" ? "Library package name" : "Plugin package name",
|
|
8011
|
+
defaultValue: defaultNameFromPath(known, kind),
|
|
8012
|
+
placeholder: defaultNameFromPath(known, kind)
|
|
7548
8013
|
});
|
|
7549
8014
|
}
|
|
7550
8015
|
if (workspaceRoot === void 0 && !install) {
|
|
@@ -7561,7 +8026,7 @@ async function createPlugin(opts = {}) {
|
|
|
7561
8026
|
});
|
|
7562
8027
|
}
|
|
7563
8028
|
const proceed = await confirm2({
|
|
7564
|
-
message: workspaceRoot !== void 0 ? `Add ${name} to the workspace at ${workspaceRoot}?` : `Create ${name} (${game}) in ${targetPath}?`,
|
|
8029
|
+
message: workspaceRoot !== void 0 ? `Add ${name} to the workspace at ${workspaceRoot}?` : kind === "library" ? `Create library ${name} in ${targetPath}?` : `Create ${name} (${game}) in ${targetPath}?`,
|
|
7565
8030
|
initialValue: true
|
|
7566
8031
|
});
|
|
7567
8032
|
if (!proceed) {
|
|
@@ -7574,28 +8039,41 @@ async function createPlugin(opts = {}) {
|
|
|
7574
8039
|
);
|
|
7575
8040
|
}
|
|
7576
8041
|
game = game ?? "cs2";
|
|
7577
|
-
name = name ?? defaultNameFromPath(targetPath);
|
|
8042
|
+
name = name ?? defaultNameFromPath(targetPath, kind);
|
|
7578
8043
|
install = workspaceRoot !== void 0 ? "none" : install ?? (opts.noInstall ? "none" : "npm");
|
|
7579
8044
|
const finalTargetPath = targetPath;
|
|
7580
8045
|
const localPackagesDir = workspaceRoot === void 0 ? findLocalPackagesDir() : void 0;
|
|
7581
|
-
|
|
8046
|
+
mkdirSync7(join21(finalTargetPath, "src"), { recursive: true });
|
|
7582
8047
|
if (workspaceRoot !== void 0) {
|
|
7583
|
-
|
|
7584
|
-
|
|
7585
|
-
|
|
8048
|
+
writeFileSync11(join21(finalTargetPath, "package.json"), minimalPackageJsonContent(name));
|
|
8049
|
+
writeFileSync11(
|
|
8050
|
+
join21(finalTargetPath, "tsconfig.json"),
|
|
7586
8051
|
workspaceTsconfigJson(finalTargetPath, workspaceRoot)
|
|
7587
8052
|
);
|
|
8053
|
+
} else if (kind === "library") {
|
|
8054
|
+
const version = readCliVersion();
|
|
8055
|
+
writeFileSync11(
|
|
8056
|
+
join21(finalTargetPath, "package.json"),
|
|
8057
|
+
libraryPackageJsonContent(name, game, version, localPackagesDir)
|
|
8058
|
+
);
|
|
8059
|
+
writeFileSync11(join21(finalTargetPath, "tsconfig.json"), tsconfigJson());
|
|
8060
|
+
writeFileSync11(join21(finalTargetPath, "eslint.config.mjs"), eslintConfig());
|
|
7588
8061
|
} else {
|
|
7589
8062
|
const version = readCliVersion();
|
|
7590
|
-
|
|
7591
|
-
|
|
8063
|
+
writeFileSync11(
|
|
8064
|
+
join21(finalTargetPath, "package.json"),
|
|
7592
8065
|
packageJsonContent(name, game, version, localPackagesDir)
|
|
7593
8066
|
);
|
|
7594
|
-
|
|
7595
|
-
|
|
8067
|
+
writeFileSync11(join21(finalTargetPath, "tsconfig.json"), tsconfigJson());
|
|
8068
|
+
writeFileSync11(join21(finalTargetPath, "eslint.config.mjs"), eslintConfig());
|
|
8069
|
+
}
|
|
8070
|
+
if (kind === "library") {
|
|
8071
|
+
writeFileSync11(join21(finalTargetPath, "src", "index.ts"), LIBRARY_ENTRY);
|
|
8072
|
+
writeFileSync11(join21(finalTargetPath, "src", "index.d.ts"), LIBRARY_TYPES);
|
|
8073
|
+
} else {
|
|
8074
|
+
writeFileSync11(join21(finalTargetPath, "src", "plugin.ts"), pluginSource(game));
|
|
7596
8075
|
}
|
|
7597
|
-
|
|
7598
|
-
writeFileSync9(join17(finalTargetPath, ".gitignore"), gitignore());
|
|
8076
|
+
writeFileSync11(join21(finalTargetPath, ".gitignore"), gitignore());
|
|
7599
8077
|
let installed = false;
|
|
7600
8078
|
if (workspaceRoot === void 0) {
|
|
7601
8079
|
if (install !== "none") {
|
|
@@ -7613,6 +8091,7 @@ async function createPlugin(opts = {}) {
|
|
|
7613
8091
|
dir: finalTargetPath,
|
|
7614
8092
|
name,
|
|
7615
8093
|
game,
|
|
8094
|
+
kind,
|
|
7616
8095
|
installed,
|
|
7617
8096
|
skippedInstall: install === "none",
|
|
7618
8097
|
packageManager: install,
|
|
@@ -7621,8 +8100,8 @@ async function createPlugin(opts = {}) {
|
|
|
7621
8100
|
}
|
|
7622
8101
|
|
|
7623
8102
|
// src/create/workspace.ts
|
|
7624
|
-
import { mkdirSync as
|
|
7625
|
-
import { join as
|
|
8103
|
+
import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync12 } from "node:fs";
|
|
8104
|
+
import { join as join22, resolve as resolve20 } from "node:path";
|
|
7626
8105
|
var ROOT_DEFAULT_GAME = "cs2";
|
|
7627
8106
|
var CHANGESETS_CLI_RANGE = "^2.29.5";
|
|
7628
8107
|
function defaultWorkspaceName(dir) {
|
|
@@ -7675,7 +8154,7 @@ function changesetConfigJson() {
|
|
|
7675
8154
|
) + "\n";
|
|
7676
8155
|
}
|
|
7677
8156
|
async function createWorkspace(opts = {}) {
|
|
7678
|
-
const targetPath =
|
|
8157
|
+
const targetPath = resolve20(opts.path ?? ".");
|
|
7679
8158
|
const interactive = isInteractive({ yes: opts.yes });
|
|
7680
8159
|
let name = opts.name;
|
|
7681
8160
|
assertEmptyTarget(targetPath);
|
|
@@ -7706,14 +8185,14 @@ async function createWorkspace(opts = {}) {
|
|
|
7706
8185
|
name = name ?? defaultWorkspaceName(targetPath);
|
|
7707
8186
|
const version = readCliVersion();
|
|
7708
8187
|
const localPackagesDir = findLocalPackagesDir();
|
|
7709
|
-
|
|
7710
|
-
|
|
7711
|
-
|
|
7712
|
-
|
|
7713
|
-
|
|
7714
|
-
|
|
7715
|
-
|
|
7716
|
-
|
|
8188
|
+
mkdirSync8(join22(targetPath, "plugins"), { recursive: true });
|
|
8189
|
+
mkdirSync8(join22(targetPath, "packages"), { recursive: true });
|
|
8190
|
+
mkdirSync8(join22(targetPath, ".changeset"), { recursive: true });
|
|
8191
|
+
writeFileSync12(join22(targetPath, "package.json"), rootPackageJsonContent(name, version, localPackagesDir));
|
|
8192
|
+
writeFileSync12(join22(targetPath, "tsconfig.base.json"), tsconfigBaseJson());
|
|
8193
|
+
writeFileSync12(join22(targetPath, "eslint.config.mjs"), eslintConfig());
|
|
8194
|
+
writeFileSync12(join22(targetPath, ".changeset", "config.json"), changesetConfigJson());
|
|
8195
|
+
writeFileSync12(join22(targetPath, ".gitignore"), gitignore());
|
|
7717
8196
|
return { dir: targetPath, name };
|
|
7718
8197
|
}
|
|
7719
8198
|
|
|
@@ -7741,7 +8220,7 @@ async function run6(argv2) {
|
|
|
7741
8220
|
return;
|
|
7742
8221
|
}
|
|
7743
8222
|
const pathArg = positionals(argv2, VALUE_FLAGS2)[0];
|
|
7744
|
-
const workspaceRoot = findWorkspaceRoot(pathArg === void 0 ? process.cwd() :
|
|
8223
|
+
const workspaceRoot = findWorkspaceRoot(pathArg === void 0 ? process.cwd() : resolve21(pathArg));
|
|
7745
8224
|
const result = await createPlugin({
|
|
7746
8225
|
path: pathArg,
|
|
7747
8226
|
name: parseFlag(argv2, "--name"),
|
|
@@ -7749,16 +8228,18 @@ async function run6(argv2) {
|
|
|
7749
8228
|
template: parseFlag(argv2, "--template"),
|
|
7750
8229
|
install: parseFlag(argv2, "--install"),
|
|
7751
8230
|
noInstall: hasFlag(argv2, "--no-install"),
|
|
8231
|
+
kind: hasFlag(argv2, "--library") ? "library" : void 0,
|
|
7752
8232
|
workspaceRoot: workspaceRoot ?? void 0,
|
|
7753
8233
|
yes
|
|
7754
8234
|
});
|
|
7755
8235
|
const next = result.workspaceRoot ? `next: npm install at the workspace root (${result.workspaceRoot}), then cd ${result.dir} && npm run build` : result.installed ? `dependencies installed (${result.packageManager})` : result.skippedInstall ? `next: cd ${result.dir} && npm run build` : `next: cd ${result.dir} && npm install && npm run build`;
|
|
8236
|
+
const libraryHint = result.kind === "library" ? " (publish with `s2s deploy`; consumers get it with `s2s add`)" : "";
|
|
7756
8237
|
if (interactive) {
|
|
7757
8238
|
log2.success(`created ${result.dir}`);
|
|
7758
|
-
outro2(next);
|
|
8239
|
+
outro2(next + libraryHint);
|
|
7759
8240
|
} else {
|
|
7760
8241
|
console.log(`created ${result.dir}`);
|
|
7761
|
-
console.log(next);
|
|
8242
|
+
console.log(next + libraryHint);
|
|
7762
8243
|
}
|
|
7763
8244
|
} catch (e) {
|
|
7764
8245
|
console.error(String(e instanceof Error ? e.message : e));
|
|
@@ -7947,8 +8428,8 @@ async function run7(argv2) {
|
|
|
7947
8428
|
}
|
|
7948
8429
|
|
|
7949
8430
|
// src/config/gen.ts
|
|
7950
|
-
import { readFileSync as
|
|
7951
|
-
import { join as
|
|
8431
|
+
import { readFileSync as readFileSync18, writeFileSync as writeFileSync13, mkdirSync as mkdirSync9 } from "node:fs";
|
|
8432
|
+
import { join as join23 } from "node:path";
|
|
7952
8433
|
|
|
7953
8434
|
// src/config/config-path.ts
|
|
7954
8435
|
function configFileName(id) {
|
|
@@ -7994,13 +8475,13 @@ function genConfigFromManifest(manifest, outDir) {
|
|
|
7994
8475
|
}
|
|
7995
8476
|
const id = typeof manifest.id === "string" ? manifest.id : "";
|
|
7996
8477
|
if (!id) throw new Error("config gen: manifest declares config but has no id");
|
|
7997
|
-
|
|
7998
|
-
const path =
|
|
7999
|
-
|
|
8478
|
+
mkdirSync9(outDir, { recursive: true });
|
|
8479
|
+
const path = join23(outDir, configFileName(id));
|
|
8480
|
+
writeFileSync13(path, generateDefaultJsonc(config));
|
|
8000
8481
|
return path;
|
|
8001
8482
|
}
|
|
8002
8483
|
function genConfigForS2sp(s2spPath, outDir) {
|
|
8003
|
-
const entry = unzipSync(
|
|
8484
|
+
const entry = unzipSync(readFileSync18(s2spPath))["manifest.json"];
|
|
8004
8485
|
if (!entry) throw new Error(`config gen: ${s2spPath} has no manifest.json`);
|
|
8005
8486
|
const manifest = JSON.parse(Buffer.from(entry).toString("utf8"));
|
|
8006
8487
|
return genConfigFromManifest(manifest, outDir);
|
|
@@ -8047,12 +8528,12 @@ async function run8(argv2) {
|
|
|
8047
8528
|
}
|
|
8048
8529
|
|
|
8049
8530
|
// src/commands/codegen.ts
|
|
8050
|
-
import { dirname as
|
|
8531
|
+
import { dirname as dirname6, join as join27 } from "node:path";
|
|
8051
8532
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
8052
8533
|
|
|
8053
8534
|
// src/schemagen/gen.ts
|
|
8054
|
-
import { readFileSync as
|
|
8055
|
-
import { join as
|
|
8535
|
+
import { readFileSync as readFileSync19, writeFileSync as writeFileSync14 } from "node:fs";
|
|
8536
|
+
import { join as join24 } from "node:path";
|
|
8056
8537
|
|
|
8057
8538
|
// src/schemagen/model.ts
|
|
8058
8539
|
function enumMemberNames(enumName, members) {
|
|
@@ -8066,8 +8547,8 @@ function enumMemberNames(enumName, members) {
|
|
|
8066
8547
|
for (const m of members) {
|
|
8067
8548
|
const up = m.toUpperCase();
|
|
8068
8549
|
let rest = null;
|
|
8069
|
-
for (const
|
|
8070
|
-
const pfx = stem +
|
|
8550
|
+
for (const sep4 of ["_", ""]) {
|
|
8551
|
+
const pfx = stem + sep4;
|
|
8071
8552
|
if (up.startsWith(pfx) && m.length > pfx.length) {
|
|
8072
8553
|
rest = m.slice(pfx.length);
|
|
8073
8554
|
break;
|
|
@@ -8431,23 +8912,23 @@ function resolveExpr(f) {
|
|
|
8431
8912
|
const base = `off(${S(f.declaringClass)},${S(f.rawName)})`;
|
|
8432
8913
|
return f.addOffset ? `${base} + ${f.addOffset}` : base;
|
|
8433
8914
|
}
|
|
8434
|
-
function accessorEntry(f,
|
|
8915
|
+
function accessorEntry(f, resolve22, guard2) {
|
|
8435
8916
|
const g = guard2 === "" ? "" : `${guard2} `;
|
|
8436
8917
|
const gs = guard2 === "" ? "" : `${guard2.replace("return null;", "return;")} `;
|
|
8437
8918
|
let entry;
|
|
8438
8919
|
if (f.accessorKind === "str") {
|
|
8439
|
-
entry = `get: function () { ${g}return this.ref.readString(${
|
|
8920
|
+
entry = `get: function () { ${g}return this.ref.readString(${resolve22}, ${f.strLen}); }`;
|
|
8440
8921
|
} else if (f.accessorKind === "u64" || f.accessorKind === "i64") {
|
|
8441
|
-
entry = `get: function () { ${g}var v = this.ref.${READ[f.accessorKind]}(${
|
|
8922
|
+
entry = `get: function () { ${g}var v = this.ref.${READ[f.accessorKind]}(${resolve22}); return v === null ? null : v.toString(); }`;
|
|
8442
8923
|
} else if (VEC_INFO[f.accessorKind]) {
|
|
8443
8924
|
const vi = VEC_INFO[f.accessorKind];
|
|
8444
|
-
entry = `get: function () { ${g}var a = this.ref.readFloats(${
|
|
8925
|
+
entry = `get: function () { ${g}var a = this.ref.readFloats(${resolve22}, ${vi.count}); return a === null ? null : new ${vi.cls}(a[0], a[1], a[2]); }`;
|
|
8445
8926
|
} else {
|
|
8446
|
-
entry = `get: function () { ${g}return this.ref.${READ[f.accessorKind]}(${
|
|
8927
|
+
entry = `get: function () { ${g}return this.ref.${READ[f.accessorKind]}(${resolve22}); }`;
|
|
8447
8928
|
}
|
|
8448
8929
|
if (f.writable) {
|
|
8449
8930
|
const wm = WRITE[f.accessorKind];
|
|
8450
|
-
entry += `, set: function (v) { ${gs}var o = ${
|
|
8931
|
+
entry += `, set: function (v) { ${gs}var o = ${resolve22}; if (this.ref.${wm}(o, v)) this.ref.notifyStateChanged(o); }`;
|
|
8451
8932
|
}
|
|
8452
8933
|
return entry;
|
|
8453
8934
|
}
|
|
@@ -8476,9 +8957,9 @@ function emitJs(model) {
|
|
|
8476
8957
|
out.push(` E[${S(e.className)}] = {`);
|
|
8477
8958
|
for (const f of e.fields) {
|
|
8478
8959
|
const sub = `off(${S(f.declaringClass)},${S(f.rawName)})`;
|
|
8479
|
-
const
|
|
8960
|
+
const resolve22 = f.addOffset ? `this.base + ${sub} + ${f.addOffset}` : `this.base + ${sub}`;
|
|
8480
8961
|
const guard2 = `if (this.base < 0 || ${sub} < 0) return null;`;
|
|
8481
|
-
out.push(` ${S(f.propName)}: { ${accessorEntry(f,
|
|
8962
|
+
out.push(` ${S(f.propName)}: { ${accessorEntry(f, resolve22, guard2)} },`);
|
|
8482
8963
|
}
|
|
8483
8964
|
for (const f of e.embeddedFields) {
|
|
8484
8965
|
const sub = `off(${S(f.declaringClass)},${S(f.rawName)})`;
|
|
@@ -8535,16 +9016,16 @@ var EMBED_PATH = "games/cs2/codegen-embedded.json";
|
|
|
8535
9016
|
var JS_OUT = "games/cs2/js/schema.generated.js";
|
|
8536
9017
|
var DTS_OUT = "packages/cs2/schema.generated.d.ts";
|
|
8537
9018
|
function runGenSchema(repoRoot2, opts) {
|
|
8538
|
-
const catalog = JSON.parse(
|
|
8539
|
-
const list = JSON.parse(
|
|
9019
|
+
const catalog = JSON.parse(readFileSync19(join24(repoRoot2, CATALOG_PATH), "utf8"));
|
|
9020
|
+
const list = JSON.parse(readFileSync19(join24(repoRoot2, LIST_PATH), "utf8"));
|
|
8540
9021
|
let embed = [];
|
|
8541
9022
|
try {
|
|
8542
|
-
embed = JSON.parse(
|
|
9023
|
+
embed = JSON.parse(readFileSync19(join24(repoRoot2, EMBED_PATH), "utf8"));
|
|
8543
9024
|
} catch {
|
|
8544
9025
|
}
|
|
8545
9026
|
let enumCatalog = {};
|
|
8546
9027
|
try {
|
|
8547
|
-
enumCatalog = JSON.parse(
|
|
9028
|
+
enumCatalog = JSON.parse(readFileSync19(join24(repoRoot2, ENUMS_PATH), "utf8"));
|
|
8548
9029
|
} catch {
|
|
8549
9030
|
}
|
|
8550
9031
|
const model = buildModel(catalog, list, embed, enumCatalog);
|
|
@@ -8555,16 +9036,16 @@ function runGenSchema(repoRoot2, opts) {
|
|
|
8555
9036
|
const drift = [];
|
|
8556
9037
|
const files = [[JS_OUT, js], [DTS_OUT, dts]];
|
|
8557
9038
|
for (const [rel, content] of files) {
|
|
8558
|
-
const abs =
|
|
9039
|
+
const abs = join24(repoRoot2, rel);
|
|
8559
9040
|
if (opts.check) {
|
|
8560
9041
|
let cur = "";
|
|
8561
9042
|
try {
|
|
8562
|
-
cur =
|
|
9043
|
+
cur = readFileSync19(abs, "utf8");
|
|
8563
9044
|
} catch {
|
|
8564
9045
|
}
|
|
8565
9046
|
if (cur !== content) drift.push(rel);
|
|
8566
9047
|
} else {
|
|
8567
|
-
|
|
9048
|
+
writeFileSync14(abs, content);
|
|
8568
9049
|
}
|
|
8569
9050
|
}
|
|
8570
9051
|
if (model.collisions.length) console.error(`gen-schema: ${model.collisions.length} name collision(s) \u2192 raw fallback:
|
|
@@ -8574,8 +9055,8 @@ function runGenSchema(repoRoot2, opts) {
|
|
|
8574
9055
|
}
|
|
8575
9056
|
|
|
8576
9057
|
// src/eventgen/gen.ts
|
|
8577
|
-
import { readFileSync as
|
|
8578
|
-
import { join as
|
|
9058
|
+
import { readFileSync as readFileSync20, writeFileSync as writeFileSync15 } from "node:fs";
|
|
9059
|
+
import { join as join25 } from "node:path";
|
|
8579
9060
|
|
|
8580
9061
|
// src/eventgen/model.ts
|
|
8581
9062
|
var TYPE_TO_GETTER = {
|
|
@@ -8660,27 +9141,27 @@ function emitEventDts(model) {
|
|
|
8660
9141
|
var CATALOG_PATH2 = "games/cs2/gamedata/event-catalog.json";
|
|
8661
9142
|
var DTS_OUT2 = "packages/cs2/events.generated.d.ts";
|
|
8662
9143
|
function runGenEvents(repoRoot2, opts) {
|
|
8663
|
-
const catalog = JSON.parse(
|
|
9144
|
+
const catalog = JSON.parse(readFileSync20(join25(repoRoot2, CATALOG_PATH2), "utf8"));
|
|
8664
9145
|
const model = buildEventModel(catalog);
|
|
8665
9146
|
const dts = emitEventDts(model);
|
|
8666
9147
|
const drift = [];
|
|
8667
|
-
const abs =
|
|
9148
|
+
const abs = join25(repoRoot2, DTS_OUT2);
|
|
8668
9149
|
if (opts.check) {
|
|
8669
9150
|
let cur = "";
|
|
8670
9151
|
try {
|
|
8671
|
-
cur =
|
|
9152
|
+
cur = readFileSync20(abs, "utf8");
|
|
8672
9153
|
} catch {
|
|
8673
9154
|
}
|
|
8674
9155
|
if (cur !== dts) drift.push(DTS_OUT2);
|
|
8675
9156
|
} else {
|
|
8676
|
-
|
|
9157
|
+
writeFileSync15(abs, dts);
|
|
8677
9158
|
}
|
|
8678
9159
|
return { events: model.length, drift };
|
|
8679
9160
|
}
|
|
8680
9161
|
|
|
8681
9162
|
// src/navgen/gen.ts
|
|
8682
|
-
import { readFileSync as
|
|
8683
|
-
import { join as
|
|
9163
|
+
import { readFileSync as readFileSync21, writeFileSync as writeFileSync16 } from "node:fs";
|
|
9164
|
+
import { join as join26 } from "node:path";
|
|
8684
9165
|
|
|
8685
9166
|
// src/navgen/model.ts
|
|
8686
9167
|
var SUPPORTED_NAV_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -8782,25 +9263,25 @@ function emitNavJs(model) {
|
|
|
8782
9263
|
for (const f of w.fields) {
|
|
8783
9264
|
const own = `off(${S2(f.declaringClass)},${S2(f.rawName)})`;
|
|
8784
9265
|
const withDelta = f.addOffset ? `${own} + ${f.addOffset}` : own;
|
|
8785
|
-
const
|
|
9266
|
+
const resolve22 = `${withDelta} + this.base`;
|
|
8786
9267
|
let getter;
|
|
8787
9268
|
const kind = f.accessorKind;
|
|
8788
9269
|
if (kind === "u64") {
|
|
8789
|
-
getter = `get: function () { var v = this.root.readUInt64Via(this.path, ${
|
|
9270
|
+
getter = `get: function () { var v = this.root.readUInt64Via(this.path, ${resolve22}); return v === null ? null : v.toString(); }`;
|
|
8790
9271
|
} else if (kind === "i64") {
|
|
8791
|
-
getter = `get: function () { var v = this.root.readInt64Via(this.path, ${
|
|
9272
|
+
getter = `get: function () { var v = this.root.readInt64Via(this.path, ${resolve22}); return v === null ? null : v.toString(); }`;
|
|
8792
9273
|
} else if (VEC_INFO[kind]) {
|
|
8793
9274
|
const vi = VEC_INFO[kind];
|
|
8794
|
-
getter = `get: function () { var a = this.root.readFloatsChain(this.path, ${
|
|
9275
|
+
getter = `get: function () { var a = this.root.readFloatsChain(this.path, ${resolve22}, ${vi.count}); return a === null ? null : new ${vi.cls}(a[0], a[1], a[2]); }`;
|
|
8795
9276
|
} else if (kind === "handle") {
|
|
8796
|
-
getter = `get: function () { return this.root.readHandleVia(this.path, ${
|
|
9277
|
+
getter = `get: function () { return this.root.readHandleVia(this.path, ${resolve22}); }`;
|
|
8797
9278
|
} else {
|
|
8798
9279
|
const method = READ_VIA[kind];
|
|
8799
9280
|
if (!method) continue;
|
|
8800
|
-
getter = `get: function () { return this.root.${method}(this.path, ${
|
|
9281
|
+
getter = `get: function () { return this.root.${method}(this.path, ${resolve22}); }`;
|
|
8801
9282
|
}
|
|
8802
9283
|
const wmethod = f.navWritable ? WRITE_VIA[kind] : void 0;
|
|
8803
|
-
const setter = wmethod ? `, set: function (v) { this.root.${wmethod}(this.path, ${
|
|
9284
|
+
const setter = wmethod ? `, set: function (v) { this.root.${wmethod}(this.path, ${resolve22}, v); }` : "";
|
|
8804
9285
|
out.push(` ${S2(f.propName)}: { ${getter}${setter} },`);
|
|
8805
9286
|
}
|
|
8806
9287
|
out.push(" });");
|
|
@@ -8901,8 +9382,8 @@ var CATALOG_PATH3 = "games/cs2/gamedata/schema-catalog.json";
|
|
|
8901
9382
|
var JS_OUT2 = "games/cs2/js/nav.generated.js";
|
|
8902
9383
|
var DTS_OUT3 = "packages/cs2/nav.generated.d.ts";
|
|
8903
9384
|
function runGenNav(repoRoot2, opts) {
|
|
8904
|
-
const config = JSON.parse(
|
|
8905
|
-
const catalog = JSON.parse(
|
|
9385
|
+
const config = JSON.parse(readFileSync21(join26(repoRoot2, TARGETS_PATH), "utf8"));
|
|
9386
|
+
const catalog = JSON.parse(readFileSync21(join26(repoRoot2, CATALOG_PATH3), "utf8"));
|
|
8906
9387
|
const model = buildNavModel(config, catalog);
|
|
8907
9388
|
const js = emitNavJs(model);
|
|
8908
9389
|
const dts = emitNavDts(model);
|
|
@@ -8910,16 +9391,16 @@ function runGenNav(repoRoot2, opts) {
|
|
|
8910
9391
|
const drift = [];
|
|
8911
9392
|
const files = [[JS_OUT2, js], [DTS_OUT3, dts]];
|
|
8912
9393
|
for (const [rel, content] of files) {
|
|
8913
|
-
const abs =
|
|
9394
|
+
const abs = join26(repoRoot2, rel);
|
|
8914
9395
|
if (opts.check) {
|
|
8915
9396
|
let cur = "";
|
|
8916
9397
|
try {
|
|
8917
|
-
cur =
|
|
9398
|
+
cur = readFileSync21(abs, "utf8");
|
|
8918
9399
|
} catch {
|
|
8919
9400
|
}
|
|
8920
9401
|
if (cur !== content) drift.push(rel);
|
|
8921
9402
|
} else {
|
|
8922
|
-
|
|
9403
|
+
writeFileSync16(abs, content);
|
|
8923
9404
|
}
|
|
8924
9405
|
}
|
|
8925
9406
|
return { wrappers: model.wrappers.length, fields, drift };
|
|
@@ -8927,7 +9408,7 @@ function runGenNav(repoRoot2, opts) {
|
|
|
8927
9408
|
|
|
8928
9409
|
// src/commands/codegen.ts
|
|
8929
9410
|
function repoRoot() {
|
|
8930
|
-
return
|
|
9411
|
+
return join27(dirname6(fileURLToPath3(import.meta.url)), "..", "..", "..");
|
|
8931
9412
|
}
|
|
8932
9413
|
async function run9(kind, argv2) {
|
|
8933
9414
|
const root = repoRoot();
|
|
@@ -9006,7 +9487,7 @@ var argv = process.argv.slice(2);
|
|
|
9006
9487
|
var command = argv[0];
|
|
9007
9488
|
function usage() {
|
|
9008
9489
|
console.error(
|
|
9009
|
-
"Usage:\n s2s create [path] [--game cs2|none] [--name <pkg>] [--template minimal]\n [--install npm|pnpm|yarn|bun|none] [--no-install] [-y]\n s2s create --workspace <dir>\n s2s build [dir|workspace root] [--filter <pattern>]... [--stamp-version <v>]\n [--packages-dir <path>]\n s2s login [--token s2s_\u2026] [--registry <url>]\n s2s deploy [dir|workspace root] [--filter <pattern>]... [--dry-run] [--yes|--ci]\n [--registry <url>] [--packages-dir <path>]\n s2s version [dir] [--since <ref>]\n s2s add <pkg>[@range] [--dir <plugin>] [--registry <url>]\n s2s install [name[@range]...] [--file <path>] [--dir <plugins dir>] [--registry <url>]\n s2s config gen <plugin.s2sp...> --out <dir>\n s2s gen-schema [--check]\n s2s gen-events [--check]\n s2s gen-nav [--check]\n\nEnv: S2SCRIPT_REGISTRY_URL S2SCRIPT_TOKEN (CI deploy)"
|
|
9490
|
+
"Usage:\n s2s create [path] [--game cs2|none] [--name <pkg>] [--template minimal] [--library]\n [--install npm|pnpm|yarn|bun|none] [--no-install] [-y]\n s2s create --workspace <dir>\n s2s build [dir|workspace root] [--filter <pattern>]... [--stamp-version <v>]\n [--packages-dir <path>]\n s2s login [--token s2s_\u2026] [--registry <url>]\n s2s deploy [dir|workspace root] [--filter <pattern>]... [--dry-run] [--yes|--ci]\n [--registry <url>] [--packages-dir <path>]\n s2s version [dir] [--since <ref>]\n s2s add <pkg>[@range] [--dir <plugin>] [--registry <url>]\n s2s install [name[@range]...] [--file <path>] [--dir <plugins dir>] [--registry <url>]\n s2s config gen <plugin.s2sp...> --out <dir>\n s2s gen-schema [--check]\n s2s gen-events [--check]\n s2s gen-nav [--check]\n\nEnv: S2SCRIPT_REGISTRY_URL S2SCRIPT_TOKEN (CI deploy)"
|
|
9010
9491
|
);
|
|
9011
9492
|
}
|
|
9012
9493
|
if (!command) {
|