@s2script/sdk 0.30.3 → 0.32.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/dist/cli.js +756 -526
- package/entity.d.ts +41 -1
- package/ext/s2ext.h +155 -0
- package/files.d.ts +56 -0
- package/index.d.ts +1 -0
- package/package.json +6 -2
- package/server.d.ts +11 -0
- package/unsafe.d.ts +142 -0
package/dist/cli.js
CHANGED
|
@@ -3455,11 +3455,11 @@ function unzipSync(data, opts) {
|
|
|
3455
3455
|
}
|
|
3456
3456
|
|
|
3457
3457
|
// src/build.ts
|
|
3458
|
-
import { readFileSync as
|
|
3459
|
-
import { resolve as resolve12, join as
|
|
3458
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, rmSync as rmSync2 } from "node:fs";
|
|
3459
|
+
import { resolve as resolve12, join as join13 } from "node:path";
|
|
3460
3460
|
|
|
3461
3461
|
// src/typecheck/typecheck.ts
|
|
3462
|
-
import
|
|
3462
|
+
import ts5 from "typescript";
|
|
3463
3463
|
|
|
3464
3464
|
// src/gamedata/load.ts
|
|
3465
3465
|
import { readFileSync } from "node:fs";
|
|
@@ -3516,9 +3516,9 @@ function stripJsonComments(src) {
|
|
|
3516
3516
|
|
|
3517
3517
|
// src/gamedata/types.ts
|
|
3518
3518
|
var PLATFORM = "linuxsteamrt64";
|
|
3519
|
-
var ARG_KINDS = ["bool", "int", "float", "string", "utlstring", "vector", "entity"];
|
|
3520
|
-
var RET_KINDS = ["void", "bool", "int", "float", "entity"];
|
|
3521
|
-
var INT_CLASS_ARGS = /* @__PURE__ */ new Set(["bool", "int", "string", "utlstring", "vector", "entity"]);
|
|
3519
|
+
var ARG_KINDS = ["bool", "int", "float", "string", "utlstring", "vector", "entity", "ptr"];
|
|
3520
|
+
var RET_KINDS = ["void", "bool", "int", "float", "entity", "ptr"];
|
|
3521
|
+
var INT_CLASS_ARGS = /* @__PURE__ */ new Set(["bool", "int", "string", "utlstring", "vector", "entity", "ptr"]);
|
|
3522
3522
|
var MAX_INT_ARGS = 9;
|
|
3523
3523
|
var MAX_FLOAT_ARGS = 8;
|
|
3524
3524
|
var HOOK_SHAPES = ["this_void", "this_f32_i32_i32_i32", "this_f32_i32_i64_i64"];
|
|
@@ -3950,14 +3950,16 @@ var ARG_TS = {
|
|
|
3950
3950
|
string: "string",
|
|
3951
3951
|
utlstring: "string",
|
|
3952
3952
|
vector: VECTOR_TS,
|
|
3953
|
-
entity: "EntityRef | null"
|
|
3953
|
+
entity: "EntityRef | null",
|
|
3954
|
+
ptr: "Ptr | null"
|
|
3954
3955
|
};
|
|
3955
3956
|
var RET_TS = {
|
|
3956
3957
|
void: "void",
|
|
3957
3958
|
bool: "boolean | null",
|
|
3958
3959
|
int: "number | null",
|
|
3959
3960
|
float: "number | null",
|
|
3960
|
-
entity: "EntityRef | null"
|
|
3961
|
+
entity: "EntityRef | null",
|
|
3962
|
+
ptr: "Ptr | null"
|
|
3961
3963
|
};
|
|
3962
3964
|
function generateGamedataTypes(gd) {
|
|
3963
3965
|
const calls = gd.calls ?? {};
|
|
@@ -3979,6 +3981,7 @@ ${lines.join("\n")}
|
|
|
3979
3981
|
"// The EntityRef import is REQUIRED: a `declare module` augmentation resolves type names in its",
|
|
3980
3982
|
"// own file scope, so an un-imported EntityRef degrades to an error skipLibCheck can swallow.",
|
|
3981
3983
|
'import type { EntityRef } from "@s2script/sdk/entity";',
|
|
3984
|
+
'import type { Ptr } from "@s2script/sdk/unsafe";',
|
|
3982
3985
|
"",
|
|
3983
3986
|
'declare module "@s2script/sdk/unsafe" {',
|
|
3984
3987
|
` interface EngineCalls {${body}}`,
|
|
@@ -3991,8 +3994,8 @@ function generateHookTypes(gd) {
|
|
|
3991
3994
|
}
|
|
3992
3995
|
|
|
3993
3996
|
// src/engine-functions/archive.ts
|
|
3994
|
-
import { existsSync, readFileSync as
|
|
3995
|
-
import { join } from "node:path";
|
|
3997
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "node:fs";
|
|
3998
|
+
import { join as join2 } from "node:path";
|
|
3996
3999
|
|
|
3997
4000
|
// src/engine-functions/parse.ts
|
|
3998
4001
|
import ts from "typescript";
|
|
@@ -4029,6 +4032,139 @@ function parseFunctionFile(path2, text3) {
|
|
|
4029
4032
|
return parsed;
|
|
4030
4033
|
}
|
|
4031
4034
|
|
|
4035
|
+
// src/engine-functions/inline.ts
|
|
4036
|
+
import { existsSync, readdirSync, readFileSync as readFileSync2, statSync } from "node:fs";
|
|
4037
|
+
import { join, relative } from "node:path";
|
|
4038
|
+
import ts2 from "typescript";
|
|
4039
|
+
var SKIP = /* @__PURE__ */ new Set(["node_modules", "dist", ".s2script", ".git"]);
|
|
4040
|
+
var SOURCE = /\.(?:ts|tsx|mts|cts)$/;
|
|
4041
|
+
var FACTORIES = /* @__PURE__ */ new Set(["fromSignature", "fromVirtual"]);
|
|
4042
|
+
function sources(dir, out = []) {
|
|
4043
|
+
for (const name of readdirSync(dir).sort()) {
|
|
4044
|
+
if (SKIP.has(name)) continue;
|
|
4045
|
+
const path2 = join(dir, name);
|
|
4046
|
+
const stat = statSync(path2);
|
|
4047
|
+
if (stat.isDirectory()) sources(path2, out);
|
|
4048
|
+
else if (SOURCE.test(name) && !name.endsWith(".d.ts")) out.push(path2);
|
|
4049
|
+
}
|
|
4050
|
+
return out;
|
|
4051
|
+
}
|
|
4052
|
+
function unwrap(node) {
|
|
4053
|
+
while (ts2.isParenthesizedExpression(node) || ts2.isAsExpression(node) || ts2.isSatisfiesExpression(node) || ts2.isTypeAssertionExpression(node)) node = node.expression;
|
|
4054
|
+
return node;
|
|
4055
|
+
}
|
|
4056
|
+
function literal(node, at) {
|
|
4057
|
+
node = unwrap(node);
|
|
4058
|
+
if (ts2.isStringLiteral(node) || ts2.isNoSubstitutionTemplateLiteral(node)) return node.text;
|
|
4059
|
+
if (ts2.isNumericLiteral(node)) return Number(node.text);
|
|
4060
|
+
if (ts2.isPrefixUnaryExpression(node) && node.operator === ts2.SyntaxKind.MinusToken && ts2.isNumericLiteral(node.operand))
|
|
4061
|
+
return -Number(node.operand.text);
|
|
4062
|
+
if (node.kind === ts2.SyntaxKind.TrueKeyword) return true;
|
|
4063
|
+
if (node.kind === ts2.SyntaxKind.FalseKeyword) return false;
|
|
4064
|
+
if (node.kind === ts2.SyntaxKind.NullKeyword) return null;
|
|
4065
|
+
if (ts2.isArrayLiteralExpression(node)) {
|
|
4066
|
+
return node.elements.map((e) => {
|
|
4067
|
+
if (ts2.isSpreadElement(e) || ts2.isOmittedExpression(e)) throw new Error(`${at(e)}: inline engine function declarations must be literals (no spreads or holes)`);
|
|
4068
|
+
return literal(e, at);
|
|
4069
|
+
});
|
|
4070
|
+
}
|
|
4071
|
+
if (ts2.isObjectLiteralExpression(node)) {
|
|
4072
|
+
const out = {};
|
|
4073
|
+
for (const prop of node.properties) {
|
|
4074
|
+
if (!ts2.isPropertyAssignment(prop)) throw new Error(`${at(prop)}: inline engine function declarations must be literals (no spreads, shorthand or methods)`);
|
|
4075
|
+
const name = prop.name;
|
|
4076
|
+
const key = ts2.isIdentifier(name) || ts2.isStringLiteral(name) || ts2.isNumericLiteral(name) ? name.text : void 0;
|
|
4077
|
+
if (key === void 0) throw new Error(`${at(prop)}: inline engine function declarations must use plain property names`);
|
|
4078
|
+
if (Object.hasOwn(out, key)) throw new Error(`${at(prop)}: duplicate key ${JSON.stringify(key)}`);
|
|
4079
|
+
out[key] = literal(prop.initializer, at);
|
|
4080
|
+
}
|
|
4081
|
+
return out;
|
|
4082
|
+
}
|
|
4083
|
+
throw new Error(`${at(node)}: inline engine function declarations must be literals, because the build copies them into the manifest; move a computed declaration to gamedata/functions.jsonc`);
|
|
4084
|
+
}
|
|
4085
|
+
function bindings(file) {
|
|
4086
|
+
const engine = /* @__PURE__ */ new Set(), namespaces = /* @__PURE__ */ new Set();
|
|
4087
|
+
for (const statement of file.statements) {
|
|
4088
|
+
if (!ts2.isImportDeclaration(statement) || !ts2.isStringLiteral(statement.moduleSpecifier)) continue;
|
|
4089
|
+
if (statement.moduleSpecifier.text !== "@s2script/sdk/unsafe") continue;
|
|
4090
|
+
const bound = statement.importClause?.namedBindings;
|
|
4091
|
+
if (!bound) continue;
|
|
4092
|
+
if (ts2.isNamespaceImport(bound)) namespaces.add(bound.name.text);
|
|
4093
|
+
else for (const element of bound.elements) {
|
|
4094
|
+
if ((element.propertyName ?? element.name).text === "Engine") engine.add(element.name.text);
|
|
4095
|
+
}
|
|
4096
|
+
}
|
|
4097
|
+
return { engine, namespaces };
|
|
4098
|
+
}
|
|
4099
|
+
function extractInlineFunctions(pluginDir) {
|
|
4100
|
+
const result = { functions: {}, sites: {} };
|
|
4101
|
+
if (!existsSync(pluginDir)) return result;
|
|
4102
|
+
for (const path2 of sources(pluginDir)) {
|
|
4103
|
+
const text3 = readFileSync2(path2, "utf8");
|
|
4104
|
+
if (!text3.includes("fromSignature") && !text3.includes("fromVirtual")) continue;
|
|
4105
|
+
const file = ts2.createSourceFile(path2, text3, ts2.ScriptTarget.Latest, true);
|
|
4106
|
+
const { engine, namespaces } = bindings(file);
|
|
4107
|
+
if (engine.size === 0 && namespaces.size === 0) continue;
|
|
4108
|
+
const at = (node) => {
|
|
4109
|
+
const { line } = file.getLineAndCharacterOfPosition(node.getStart(file));
|
|
4110
|
+
return `${relative(pluginDir, path2)}:${line + 1}`;
|
|
4111
|
+
};
|
|
4112
|
+
const isEngine = (node) => ts2.isIdentifier(node) && engine.has(node.text) || ts2.isPropertyAccessExpression(node) && node.name.text === "Engine" && ts2.isIdentifier(node.expression) && namespaces.has(node.expression.text);
|
|
4113
|
+
const visit = (node) => {
|
|
4114
|
+
if (ts2.isPropertyAccessExpression(node) && FACTORIES.has(node.name.text) && isEngine(node.expression)) {
|
|
4115
|
+
const factory = node.name.text;
|
|
4116
|
+
const call = node.parent;
|
|
4117
|
+
if (!ts2.isCallExpression(call) || call.expression !== node)
|
|
4118
|
+
throw new Error(`${at(node)}: Engine.${factory} must be called directly, so the build can read its declaration`);
|
|
4119
|
+
const [nameArg, declArg] = call.arguments;
|
|
4120
|
+
if (call.arguments.length !== 2 || !nameArg || !declArg)
|
|
4121
|
+
throw new Error(`${at(call)}: Engine.${factory}(name, declaration) takes exactly two arguments`);
|
|
4122
|
+
const name = literal(nameArg, at);
|
|
4123
|
+
if (typeof name !== "string") throw new Error(`${at(nameArg)}: Engine.${factory} needs a string-literal name`);
|
|
4124
|
+
const decl = literal(declArg, at);
|
|
4125
|
+
if (decl === null || typeof decl !== "object" || Array.isArray(decl))
|
|
4126
|
+
throw new Error(`${at(declArg)}: Engine.${factory} needs an object-literal declaration`);
|
|
4127
|
+
const target2 = decl.target;
|
|
4128
|
+
if (target2 === null || typeof target2 !== "object" || Array.isArray(target2))
|
|
4129
|
+
throw new Error(`${at(declArg)}: Engine.${factory}: declaration.target must be an object`);
|
|
4130
|
+
const kind = target2.kind;
|
|
4131
|
+
if ("ref" in target2) {
|
|
4132
|
+
} else if (factory === "fromVirtual") {
|
|
4133
|
+
if (kind !== void 0 && kind !== "virtual") throw new Error(`${at(declArg)}: Engine.fromVirtual needs a virtual target`);
|
|
4134
|
+
target2.kind = "virtual";
|
|
4135
|
+
} else if (kind !== void 0 && kind !== "signature") {
|
|
4136
|
+
throw new Error(`${at(declArg)}: Engine.fromSignature needs a signature target; use Engine.fromVirtual for a vtable slot`);
|
|
4137
|
+
}
|
|
4138
|
+
if (Object.hasOwn(result.functions, name))
|
|
4139
|
+
throw new Error(`${at(call)}: engine function ${JSON.stringify(name)} is already declared inline at ${result.sites[name]}`);
|
|
4140
|
+
result.functions[name] = decl;
|
|
4141
|
+
result.sites[name] = at(call);
|
|
4142
|
+
}
|
|
4143
|
+
ts2.forEachChild(node, visit);
|
|
4144
|
+
};
|
|
4145
|
+
visit(file);
|
|
4146
|
+
}
|
|
4147
|
+
return result;
|
|
4148
|
+
}
|
|
4149
|
+
function mergeInlineFunctions(file, inline) {
|
|
4150
|
+
const names = Object.keys(inline.functions);
|
|
4151
|
+
if (names.length === 0) return file;
|
|
4152
|
+
const merged = file ? { ...file, functions: { ...file.functions ?? {} } } : { schemaVersion: 2, functions: {} };
|
|
4153
|
+
for (const name of names) {
|
|
4154
|
+
if (Object.hasOwn(merged.functions, name))
|
|
4155
|
+
throw new Error(`${inline.sites[name]}: engine function ${JSON.stringify(name)} is declared both inline and in gamedata/functions.jsonc`);
|
|
4156
|
+
merged.functions[name] = inline.functions[name];
|
|
4157
|
+
}
|
|
4158
|
+
return merged;
|
|
4159
|
+
}
|
|
4160
|
+
function locateInlineError(error, inline) {
|
|
4161
|
+
const err2 = error instanceof Error ? error : new Error(String(error));
|
|
4162
|
+
for (const [name, site] of Object.entries(inline.sites)) {
|
|
4163
|
+
if (err2.message.startsWith(`function ${JSON.stringify(name)}`)) return new Error(`${site}: ${err2.message} (declared inline)`);
|
|
4164
|
+
}
|
|
4165
|
+
return err2;
|
|
4166
|
+
}
|
|
4167
|
+
|
|
4032
4168
|
// src/engine-functions/abi.generated.ts
|
|
4033
4169
|
var PLATFORM2 = "linux-x86_64-sysv";
|
|
4034
4170
|
var RECEIVERS = ["none", "entity"];
|
|
@@ -4062,7 +4198,7 @@ var IDENTIFIER2 = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
|
4062
4198
|
var FORBIDDEN_NAMES = /* @__PURE__ */ new Set(["self", "returnValue", "constructor", "prototype", "__proto__"]);
|
|
4063
4199
|
var SURFACES = ["call", "pre", "post"];
|
|
4064
4200
|
var RESOLVERS = ["direct", "ctor-body-xref", "lea-disp", "validated-call"];
|
|
4065
|
-
var TYPES = ["bool", "i32", "u32", "i64", "u64", "f32", "f64", "entity", "entity?", "string", "vector"];
|
|
4201
|
+
var TYPES = ["bool", "i32", "u32", "i64", "u64", "f32", "f64", "entity", "entity?", "string", "vector", "ptr"];
|
|
4066
4202
|
var PARAMETER_OWNERSHIP = ["callee-borrowed", "callee-retained", "native-observed"];
|
|
4067
4203
|
var RETURN_OWNERSHIP = ["caller-borrowed", "native-observed"];
|
|
4068
4204
|
var copied = (type) => type === "string" || type === "vector";
|
|
@@ -4137,7 +4273,7 @@ function projection(type, where2) {
|
|
|
4137
4273
|
if (type === "void") return { native: "void", projection: { id: "void", version: 1 } };
|
|
4138
4274
|
if (!TYPES.includes(type)) throw new Error(`${where2}: unsupported author type ${JSON.stringify(type)}`);
|
|
4139
4275
|
if (type === "bool") return { native: "u8", projection: { id: "bool", version: 1 } };
|
|
4140
|
-
if (type === "entity" || type === "entity?" || type === "string" || type === "vector") {
|
|
4276
|
+
if (type === "entity" || type === "entity?" || type === "string" || type === "vector" || type === "ptr") {
|
|
4141
4277
|
return { native: "ptr", projection: { id: type, version: 1 } };
|
|
4142
4278
|
}
|
|
4143
4279
|
return { native: type, projection: { id: type, version: 1 } };
|
|
@@ -4273,9 +4409,15 @@ function summarizeFunctions(bundle) {
|
|
|
4273
4409
|
|
|
4274
4410
|
// src/engine-functions/archive.ts
|
|
4275
4411
|
function loadEngineFunctions(pluginDir, ownerId) {
|
|
4276
|
-
const path2 =
|
|
4277
|
-
|
|
4278
|
-
|
|
4412
|
+
const path2 = join2(pluginDir, "gamedata", "functions.jsonc");
|
|
4413
|
+
const file = existsSync2(path2) ? parseFunctionFile(path2, readFileSync3(path2, "utf8")) : void 0;
|
|
4414
|
+
const inline = extractInlineFunctions(pluginDir);
|
|
4415
|
+
const merged = mergeInlineFunctions(file, inline);
|
|
4416
|
+
try {
|
|
4417
|
+
return normalizeFunctions(ownerId, merged);
|
|
4418
|
+
} catch (error) {
|
|
4419
|
+
throw locateInlineError(error, inline);
|
|
4420
|
+
}
|
|
4279
4421
|
}
|
|
4280
4422
|
function engineFunctionsArchive(bundle) {
|
|
4281
4423
|
return canonicalJson(bundle) + "\n";
|
|
@@ -4308,6 +4450,9 @@ function typeOf(projection2) {
|
|
|
4308
4450
|
return "string";
|
|
4309
4451
|
case "vector":
|
|
4310
4452
|
return "{ readonly x: number; readonly y: number; readonly z: number }";
|
|
4453
|
+
// A raw address: a `Ptr` from this module (in scope inside the augmentation), null for 0.
|
|
4454
|
+
case "ptr":
|
|
4455
|
+
return "Ptr | null";
|
|
4311
4456
|
default:
|
|
4312
4457
|
throw new Error(`no public TypeScript projection for ${projection2.id}`);
|
|
4313
4458
|
}
|
|
@@ -4382,27 +4527,27 @@ function emitEngineFunctionTypes(bundle) {
|
|
|
4382
4527
|
}
|
|
4383
4528
|
|
|
4384
4529
|
// src/interop.ts
|
|
4385
|
-
import
|
|
4530
|
+
import ts4 from "typescript";
|
|
4386
4531
|
import { createHash as createHash2 } from "node:crypto";
|
|
4387
4532
|
|
|
4388
4533
|
// src/publish-scan.ts
|
|
4389
|
-
import
|
|
4534
|
+
import ts3 from "typescript";
|
|
4390
4535
|
function pluginApiName(checker, call) {
|
|
4391
4536
|
const declaration = checker.getResolvedSignature(call)?.getDeclaration();
|
|
4392
4537
|
if (!declaration || !declaration.getSourceFile().fileName.replace(/\\/g, "/").endsWith("/sdk/plugin.d.ts"))
|
|
4393
4538
|
return void 0;
|
|
4394
4539
|
const name = declaration.name;
|
|
4395
|
-
return name && (
|
|
4540
|
+
return name && (ts3.isIdentifier(name) || ts3.isStringLiteral(name)) ? name.text : void 0;
|
|
4396
4541
|
}
|
|
4397
4542
|
function recordPublishOrUse(out, method, arg0, sf, node) {
|
|
4398
4543
|
if (method === "publish") {
|
|
4399
|
-
if (arg0 !== void 0 &&
|
|
4544
|
+
if (arg0 !== void 0 && ts3.isStringLiteralLike(arg0)) {
|
|
4400
4545
|
out.publishNames.push(arg0.text);
|
|
4401
4546
|
} else {
|
|
4402
4547
|
const { line } = sf.getLineAndCharacterOfPosition(node.getStart());
|
|
4403
4548
|
out.dynamicPublishSites.push(`${sf.fileName}:${line + 1}`);
|
|
4404
4549
|
}
|
|
4405
|
-
} else if (arg0 !== void 0 &&
|
|
4550
|
+
} else if (arg0 !== void 0 && ts3.isStringLiteralLike(arg0)) {
|
|
4406
4551
|
out.useNames.push(arg0.text);
|
|
4407
4552
|
}
|
|
4408
4553
|
}
|
|
@@ -4423,10 +4568,10 @@ function scanPluginProgram(program, pluginDir) {
|
|
|
4423
4568
|
if (sf.isDeclarationFile) continue;
|
|
4424
4569
|
if (!sf.fileName.replace(/\\/g, "/").startsWith(dirPrefix)) continue;
|
|
4425
4570
|
const visit = (node) => {
|
|
4426
|
-
if ((
|
|
4571
|
+
if ((ts3.isImportDeclaration(node) || ts3.isExportDeclaration(node)) && node.moduleSpecifier !== void 0 && ts3.isStringLiteralLike(node.moduleSpecifier)) {
|
|
4427
4572
|
recordImportSpecifier(out, node.moduleSpecifier.text);
|
|
4428
4573
|
}
|
|
4429
|
-
if (
|
|
4574
|
+
if (ts3.isCallExpression(node)) {
|
|
4430
4575
|
const name = pluginApiName(checker, node);
|
|
4431
4576
|
if (name && [
|
|
4432
4577
|
"publish",
|
|
@@ -4437,7 +4582,7 @@ function scanPluginProgram(program, pluginDir) {
|
|
|
4437
4582
|
].includes(name))
|
|
4438
4583
|
recordPublishOrUse(out, name, node.arguments[0], sf, node);
|
|
4439
4584
|
}
|
|
4440
|
-
|
|
4585
|
+
ts3.forEachChild(node, visit);
|
|
4441
4586
|
};
|
|
4442
4587
|
visit(sf);
|
|
4443
4588
|
}
|
|
@@ -4499,8 +4644,8 @@ function canonical(value) {
|
|
|
4499
4644
|
throw new Error("canonical metadata requires JSON values");
|
|
4500
4645
|
}
|
|
4501
4646
|
function extractContract(path2, packagesDir) {
|
|
4502
|
-
const program =
|
|
4503
|
-
...sharedProgramOptions(
|
|
4647
|
+
const program = ts4.createProgram([path2], {
|
|
4648
|
+
...sharedProgramOptions(ts4),
|
|
4504
4649
|
skipLibCheck: false,
|
|
4505
4650
|
baseUrl: packagesDir,
|
|
4506
4651
|
paths: { "@s2script/sdk": ["sdk/index.d.ts"], "@s2script/sdk/*": ["sdk/*.d.ts"] }
|
|
@@ -4514,11 +4659,11 @@ function extractContract(path2, packagesDir) {
|
|
|
4514
4659
|
);
|
|
4515
4660
|
};
|
|
4516
4661
|
const visitImports = (node) => {
|
|
4517
|
-
if (
|
|
4518
|
-
const module2 =
|
|
4519
|
-
const
|
|
4662
|
+
if (ts4.isImportDeclaration(node)) {
|
|
4663
|
+
const module2 = ts4.isStringLiteral(node.moduleSpecifier) ? node.moduleSpecifier.text : "";
|
|
4664
|
+
const bindings2 = node.importClause?.namedBindings;
|
|
4520
4665
|
const allowed = module2 === "@s2script/sdk/interfaces" ? ["Notification", "Hook", "Transform"] : module2 === "@s2script/sdk/events" || module2 === "@s2script/sdk" ? ["HookResultValue"] : module2 === "@s2script/sdk/entity" ? ["EntityRef"] : [];
|
|
4521
|
-
if (!
|
|
4666
|
+
if (!bindings2 || !ts4.isNamedImports(bindings2) || node.importClause?.name || !bindings2.elements.every(
|
|
4522
4667
|
(e) => allowed.includes((e.propertyName ?? e.name).text)
|
|
4523
4668
|
))
|
|
4524
4669
|
fail(
|
|
@@ -4526,12 +4671,12 @@ function extractContract(path2, packagesDir) {
|
|
|
4526
4671
|
"contracts must be self-contained; only SDK Notification, Hook, Transform, HookResultValue and EntityRef imports are supported"
|
|
4527
4672
|
);
|
|
4528
4673
|
}
|
|
4529
|
-
if (
|
|
4674
|
+
if (ts4.isExportDeclaration(node) && node.moduleSpecifier || ts4.isImportTypeNode(node) || ts4.isImportEqualsDeclaration(node) || ts4.isModuleDeclaration(node))
|
|
4530
4675
|
fail(
|
|
4531
4676
|
node,
|
|
4532
4677
|
"external declarations and module augmentations are not supported in a contract"
|
|
4533
4678
|
);
|
|
4534
|
-
|
|
4679
|
+
ts4.forEachChild(node, visitImports);
|
|
4535
4680
|
};
|
|
4536
4681
|
visitImports(sf);
|
|
4537
4682
|
if (sf.referencedFiles.length || sf.typeReferenceDirectives.length)
|
|
@@ -4541,7 +4686,7 @@ function extractContract(path2, packagesDir) {
|
|
|
4541
4686
|
...program.getSemanticDiagnostics(sf)
|
|
4542
4687
|
];
|
|
4543
4688
|
if (diags.length)
|
|
4544
|
-
fail(sf,
|
|
4689
|
+
fail(sf, ts4.flattenDiagnosticMessageText(diags[0].messageText, "\n"));
|
|
4545
4690
|
const module = checker.getSymbolAtLocation(sf);
|
|
4546
4691
|
const symbol2 = module && checker.getExportsOfModule(module).find((s) => s.name === "Contract");
|
|
4547
4692
|
if (!symbol2) fail(sf, "protocol 2 requires an exported Contract");
|
|
@@ -4553,26 +4698,26 @@ function extractContract(path2, packagesDir) {
|
|
|
4553
4698
|
};
|
|
4554
4699
|
for (const name of ["methods", "forwards"]) {
|
|
4555
4700
|
const member = prop(contract, name, sf);
|
|
4556
|
-
if (!(member.flags &
|
|
4701
|
+
if (!(member.flags & ts4.TypeFlags.Object) || member.getCallSignatures().length || checker.getIndexInfosOfType(member).length) {
|
|
4557
4702
|
fail(sf, `${name} must be a finite object record`);
|
|
4558
4703
|
}
|
|
4559
4704
|
}
|
|
4560
4705
|
const stack = /* @__PURE__ */ new Set();
|
|
4561
4706
|
const schema = (type, node, voidAllowed = false) => {
|
|
4562
4707
|
const f = type.flags;
|
|
4563
|
-
if (f &
|
|
4708
|
+
if (f & ts4.TypeFlags.Any || f & ts4.TypeFlags.Unknown || f & ts4.TypeFlags.Never)
|
|
4564
4709
|
fail(node, `unsupported wire type ${checker.typeToString(type)}`);
|
|
4565
|
-
if (f &
|
|
4566
|
-
if (f &
|
|
4567
|
-
if (f &
|
|
4710
|
+
if (f & ts4.TypeFlags.Void && voidAllowed) return { kind: "void" };
|
|
4711
|
+
if (f & ts4.TypeFlags.Null) return { kind: "null" };
|
|
4712
|
+
if (f & ts4.TypeFlags.StringLiteral)
|
|
4568
4713
|
return { kind: "literal", value: type.value };
|
|
4569
|
-
if (f &
|
|
4714
|
+
if (f & ts4.TypeFlags.NumberLiteral)
|
|
4570
4715
|
return { kind: "literal", value: type.value };
|
|
4571
|
-
if (f &
|
|
4716
|
+
if (f & ts4.TypeFlags.BooleanLiteral)
|
|
4572
4717
|
return { kind: "literal", value: checker.typeToString(type) === "true" };
|
|
4573
|
-
if (f &
|
|
4574
|
-
if (f &
|
|
4575
|
-
if (f &
|
|
4718
|
+
if (f & ts4.TypeFlags.String) return { kind: "string" };
|
|
4719
|
+
if (f & ts4.TypeFlags.Number) return { kind: "number" };
|
|
4720
|
+
if (f & ts4.TypeFlags.Boolean) return { kind: "boolean" };
|
|
4576
4721
|
if (stack.has(type)) fail(node, "recursive wire types are unsupported");
|
|
4577
4722
|
stack.add(type);
|
|
4578
4723
|
try {
|
|
@@ -4595,7 +4740,7 @@ function extractContract(path2, packagesDir) {
|
|
|
4595
4740
|
node
|
|
4596
4741
|
)
|
|
4597
4742
|
};
|
|
4598
|
-
if (!(f &
|
|
4743
|
+
if (!(f & ts4.TypeFlags.Object) || checker.isTupleType(type) || type.getCallSignatures().length || checker.getIndexInfosOfType(type).length)
|
|
4599
4744
|
fail(node, `unsupported wire type ${checker.typeToString(type)}`);
|
|
4600
4745
|
const sym = type.getSymbol();
|
|
4601
4746
|
if (sym?.name === "EntityRef" && sym.declarations?.some(
|
|
@@ -4603,7 +4748,7 @@ function extractContract(path2, packagesDir) {
|
|
|
4603
4748
|
))
|
|
4604
4749
|
return { kind: "entityRef" };
|
|
4605
4750
|
if (sym?.declarations?.some(
|
|
4606
|
-
(d) =>
|
|
4751
|
+
(d) => ts4.isClassDeclaration(d) || d.getSourceFile() !== sf
|
|
4607
4752
|
))
|
|
4608
4753
|
fail(
|
|
4609
4754
|
node,
|
|
@@ -4614,11 +4759,11 @@ function extractContract(path2, packagesDir) {
|
|
|
4614
4759
|
const decl = p.valueDeclaration ?? node;
|
|
4615
4760
|
if (p.name === "__s2ref")
|
|
4616
4761
|
fail(decl, "__s2ref is reserved for the EntityRef wire encoding");
|
|
4617
|
-
const optional = !!(p.flags &
|
|
4762
|
+
const optional = !!(p.flags & ts4.SymbolFlags.Optional);
|
|
4618
4763
|
let t2 = checker.getTypeOfSymbolAtLocation(p, decl);
|
|
4619
4764
|
if (optional && t2.isUnion()) {
|
|
4620
4765
|
const parts = t2.types.filter(
|
|
4621
|
-
(t3) => !(t3.flags &
|
|
4766
|
+
(t3) => !(t3.flags & ts4.TypeFlags.Undefined)
|
|
4622
4767
|
);
|
|
4623
4768
|
if (parts.length === 1) t2 = parts[0];
|
|
4624
4769
|
else {
|
|
@@ -4642,13 +4787,13 @@ function extractContract(path2, packagesDir) {
|
|
|
4642
4787
|
const methods = /* @__PURE__ */ Object.create(null);
|
|
4643
4788
|
for (const p of prop(contract, "methods", sf).getProperties()) {
|
|
4644
4789
|
const node = p.valueDeclaration ?? sf, type = checker.getTypeOfSymbolAtLocation(p, node), sigs = type.getCallSignatures();
|
|
4645
|
-
const scanner =
|
|
4646
|
-
|
|
4790
|
+
const scanner = ts4.createScanner(
|
|
4791
|
+
ts4.ScriptTarget.ESNext,
|
|
4647
4792
|
false,
|
|
4648
|
-
|
|
4793
|
+
ts4.LanguageVariant.Standard,
|
|
4649
4794
|
p.name
|
|
4650
4795
|
);
|
|
4651
|
-
const identifier = scanner.scan() ===
|
|
4796
|
+
const identifier = scanner.scan() === ts4.SyntaxKind.Identifier && scanner.scan() === ts4.SyntaxKind.EndOfFileToken;
|
|
4652
4797
|
if (!identifier || ["on", "off", "then"].includes(p.name))
|
|
4653
4798
|
fail(node, `unsupported or reserved method name ${p.name}`);
|
|
4654
4799
|
const exported = checker.getExportsOfModule(module).find((s) => s.name === p.name);
|
|
@@ -4666,7 +4811,7 @@ function extractContract(path2, packagesDir) {
|
|
|
4666
4811
|
)
|
|
4667
4812
|
)))
|
|
4668
4813
|
fail(node, `export ${p.name} must agree with Contract.methods`);
|
|
4669
|
-
if (sigs.length !== 1 || sigs[0].typeParameters?.length || p.flags &
|
|
4814
|
+
if (sigs.length !== 1 || sigs[0].typeParameters?.length || p.flags & ts4.SymbolFlags.Optional)
|
|
4670
4815
|
fail(node, "methods require one non-generic synchronous signature");
|
|
4671
4816
|
const sig = sigs[0];
|
|
4672
4817
|
methods[p.name] = {
|
|
@@ -4676,7 +4821,7 @@ function extractContract(path2, packagesDir) {
|
|
|
4676
4821
|
let t2 = checker.getTypeOfSymbolAtLocation(p2, d);
|
|
4677
4822
|
if (d.questionToken && t2.isUnion()) {
|
|
4678
4823
|
const parts = t2.types.filter(
|
|
4679
|
-
(t3) => !(t3.flags &
|
|
4824
|
+
(t3) => !(t3.flags & ts4.TypeFlags.Undefined)
|
|
4680
4825
|
);
|
|
4681
4826
|
if (parts.length === 1) t2 = parts[0];
|
|
4682
4827
|
else fail(d, "optional union arguments are unsupported");
|
|
@@ -4714,9 +4859,9 @@ function extractContract(path2, packagesDir) {
|
|
|
4714
4859
|
if (payload.kind !== "object")
|
|
4715
4860
|
fail(node, "Transform requires a finite object payload");
|
|
4716
4861
|
const writableType = prop(type, "__transformWritable", node);
|
|
4717
|
-
const keys2 = writableType.flags &
|
|
4862
|
+
const keys2 = writableType.flags & ts4.TypeFlags.Never ? [] : writableType.isUnion() ? writableType.types : [writableType];
|
|
4718
4863
|
const writable = keys2.map((t2) => {
|
|
4719
|
-
if (!(t2.flags &
|
|
4864
|
+
if (!(t2.flags & ts4.TypeFlags.StringLiteral))
|
|
4720
4865
|
fail(node, "Transform writable keys must be string field names");
|
|
4721
4866
|
const key2 = t2.value;
|
|
4722
4867
|
if (!Object.hasOwn(payload.fields, key2))
|
|
@@ -4728,10 +4873,10 @@ function extractContract(path2, packagesDir) {
|
|
|
4728
4873
|
}
|
|
4729
4874
|
for (const exported of checker.getExportsOfModule(module)) {
|
|
4730
4875
|
const typeOnly = exported.declarations?.every(
|
|
4731
|
-
(d) =>
|
|
4876
|
+
(d) => ts4.isExportSpecifier(d) && (d.isTypeOnly || ts4.isExportDeclaration(d.parent.parent) && d.parent.parent.isTypeOnly)
|
|
4732
4877
|
);
|
|
4733
|
-
const target2 = exported.flags &
|
|
4734
|
-
if (!typeOnly && target2.flags &
|
|
4878
|
+
const target2 = exported.flags & ts4.SymbolFlags.Alias ? checker.getAliasedSymbol(exported) : exported;
|
|
4879
|
+
if (!typeOnly && target2.flags & ts4.SymbolFlags.Value && !Object.hasOwn(methods, exported.name))
|
|
4735
4880
|
fail(exported.declarations?.[0] ?? sf, `unsupported value export ${exported.name}; only Contract.methods may export runtime values`);
|
|
4736
4881
|
}
|
|
4737
4882
|
const metadata = { version: 1, methods, forwards };
|
|
@@ -4751,40 +4896,40 @@ function implementationExpression(checker, expression, seen = /* @__PURE__ */ ne
|
|
|
4751
4896
|
const declarationValue = (declaration) => {
|
|
4752
4897
|
if (seen.has(declaration)) return void 0;
|
|
4753
4898
|
seen.add(declaration);
|
|
4754
|
-
if ((
|
|
4899
|
+
if ((ts4.isVariableDeclaration(declaration) || ts4.isPropertyAssignment(declaration)) && declaration.initializer)
|
|
4755
4900
|
return implementationExpression(checker, declaration.initializer, seen);
|
|
4756
|
-
if (
|
|
4901
|
+
if (ts4.isShorthandPropertyAssignment(declaration)) {
|
|
4757
4902
|
const value = checker.getShorthandAssignmentValueSymbol(
|
|
4758
4903
|
declaration
|
|
4759
4904
|
)?.valueDeclaration;
|
|
4760
4905
|
return value && declarationValue(value);
|
|
4761
4906
|
}
|
|
4762
|
-
if (
|
|
4907
|
+
if (ts4.isBindingElement(declaration) && ts4.isObjectBindingPattern(declaration.parent)) {
|
|
4763
4908
|
const object2 = declarationValue(declaration.parent.parent);
|
|
4764
4909
|
const name = declaration.propertyName ?? declaration.name;
|
|
4765
|
-
if (object2 && (
|
|
4910
|
+
if (object2 && (ts4.isIdentifier(name) || ts4.isStringLiteral(name)))
|
|
4766
4911
|
return propertyValue(object2, name.text);
|
|
4767
4912
|
}
|
|
4768
4913
|
return void 0;
|
|
4769
4914
|
};
|
|
4770
|
-
if (
|
|
4915
|
+
if (ts4.isParenthesizedExpression(expression))
|
|
4771
4916
|
return implementationExpression(checker, expression.expression, seen);
|
|
4772
|
-
if (
|
|
4917
|
+
if (ts4.isPropertyAccessExpression(expression))
|
|
4773
4918
|
return propertyValue(expression.expression, expression.name.text) ?? expression;
|
|
4774
|
-
if (
|
|
4919
|
+
if (ts4.isElementAccessExpression(expression) && ts4.isStringLiteralLike(expression.argumentExpression))
|
|
4775
4920
|
return propertyValue(
|
|
4776
4921
|
expression.expression,
|
|
4777
4922
|
expression.argumentExpression.text
|
|
4778
4923
|
) ?? expression;
|
|
4779
4924
|
let symbol2 = checker.getSymbolAtLocation(expression);
|
|
4780
|
-
if (symbol2 && symbol2.flags &
|
|
4925
|
+
if (symbol2 && symbol2.flags & ts4.SymbolFlags.Alias)
|
|
4781
4926
|
symbol2 = checker.getAliasedSymbol(symbol2);
|
|
4782
4927
|
return (symbol2?.valueDeclaration && declarationValue(symbol2.valueDeclaration)) ?? expression;
|
|
4783
4928
|
}
|
|
4784
4929
|
function checkInteropCalls(program, paths, publishes, generatedPath, pluginDir, dependencies, optionalDependencies) {
|
|
4785
4930
|
const checker = program.getTypeChecker(), out = [];
|
|
4786
4931
|
const report = (node, message) => out.push({
|
|
4787
|
-
category:
|
|
4932
|
+
category: ts4.DiagnosticCategory.Error,
|
|
4788
4933
|
code: 92002,
|
|
4789
4934
|
file: node.getSourceFile(),
|
|
4790
4935
|
start: node.getStart(),
|
|
@@ -4804,12 +4949,12 @@ function checkInteropCalls(program, paths, publishes, generatedPath, pluginDir,
|
|
|
4804
4949
|
);
|
|
4805
4950
|
for (const sf of program.getSourceFiles()) {
|
|
4806
4951
|
const visit = (node) => {
|
|
4807
|
-
if (
|
|
4952
|
+
if (ts4.isInterfaceDeclaration(node) && node.name.text === "InterfaceContracts" && sf.fileName !== generatedPath && sf.fileName !== sdkInterfaces)
|
|
4808
4953
|
report(
|
|
4809
4954
|
node,
|
|
4810
4955
|
"InterfaceContracts associations are generated; local augmentation is not authority"
|
|
4811
4956
|
);
|
|
4812
|
-
if (
|
|
4957
|
+
if (ts4.isCallExpression(node) && sf.fileName.startsWith(pluginDir + "/")) {
|
|
4813
4958
|
const method = pluginApiName(checker, node);
|
|
4814
4959
|
if ([
|
|
4815
4960
|
"publish",
|
|
@@ -4819,7 +4964,7 @@ function checkInteropCalls(program, paths, publishes, generatedPath, pluginDir,
|
|
|
4819
4964
|
"bindForwards"
|
|
4820
4965
|
].includes(method ?? "")) {
|
|
4821
4966
|
const arg = node.arguments[0];
|
|
4822
|
-
const name = arg &&
|
|
4967
|
+
const name = arg && ts4.isStringLiteralLike(arg) ? arg.text : null;
|
|
4823
4968
|
if (!name || !contracts.has(name))
|
|
4824
4969
|
report(
|
|
4825
4970
|
node,
|
|
@@ -4838,8 +4983,8 @@ function checkInteropCalls(program, paths, publishes, generatedPath, pluginDir,
|
|
|
4838
4983
|
if (method === "watchOptional" && node.arguments[1]) {
|
|
4839
4984
|
const callback = node.arguments[1];
|
|
4840
4985
|
const type = checker.getTypeAtLocation(implementationExpression(checker, callback));
|
|
4841
|
-
const asynchronous = (type2) => type2.isUnion() ? type2.types.some(asynchronous) : !!(type2.flags &
|
|
4842
|
-
if (type.flags &
|
|
4986
|
+
const asynchronous = (type2) => type2.isUnion() ? type2.types.some(asynchronous) : !!(type2.flags & ts4.TypeFlags.Any) || !!type2.getProperty("then");
|
|
4987
|
+
if (type.flags & ts4.TypeFlags.Any || type.getCallSignatures().some((signature) => asynchronous(checker.getReturnTypeOfSignature(signature))))
|
|
4843
4988
|
report(callback, "watchOptional requires a synchronous attachment callback; thenables are forbidden");
|
|
4844
4989
|
}
|
|
4845
4990
|
if (method === "publish") {
|
|
@@ -4855,7 +5000,7 @@ function checkInteropCalls(program, paths, publishes, generatedPath, pluginDir,
|
|
|
4855
5000
|
const implementationType = impl && checker.getTypeAtLocation(
|
|
4856
5001
|
implementationExpression(checker, impl)
|
|
4857
5002
|
);
|
|
4858
|
-
if (!actual || actual.flags &
|
|
5003
|
+
if (!actual || actual.flags & ts4.TypeFlags.Any || !checker.isTypeAssignableTo(actual, expected))
|
|
4859
5004
|
report(
|
|
4860
5005
|
impl ?? node,
|
|
4861
5006
|
`producer implementation must agree with ${name} Contract.methods (${checker.typeToString(
|
|
@@ -4880,7 +5025,7 @@ function checkInteropCalls(program, paths, publishes, generatedPath, pluginDir,
|
|
|
4880
5025
|
if (!implementation) continue;
|
|
4881
5026
|
const required = checker.getTypeOfSymbolAtLocation(expectedMethod, impl).getCallSignatures()[0];
|
|
4882
5027
|
const declaration = implementation.valueDeclaration;
|
|
4883
|
-
const value = declaration &&
|
|
5028
|
+
const value = declaration && ts4.isPropertyAssignment(declaration) ? declaration.initializer : declaration && ts4.isShorthandPropertyAssignment(declaration) ? declaration.name : void 0;
|
|
4884
5029
|
const methodType = value ? checker.getTypeAtLocation(
|
|
4885
5030
|
implementationExpression(checker, value)
|
|
4886
5031
|
) : checker.getTypeOfSymbolAtLocation(implementation, impl);
|
|
@@ -4895,15 +5040,15 @@ function checkInteropCalls(program, paths, publishes, generatedPath, pluginDir,
|
|
|
4895
5040
|
const provided = signatures[0];
|
|
4896
5041
|
const result = checker.getReturnTypeOfSignature(provided);
|
|
4897
5042
|
const expectedResult = checker.getReturnTypeOfSignature(required);
|
|
4898
|
-
const resultMatches = expectedResult.flags &
|
|
4899
|
-
if (result.flags &
|
|
5043
|
+
const resultMatches = expectedResult.flags & ts4.TypeFlags.Void ? !!(result.flags & (ts4.TypeFlags.Void | ts4.TypeFlags.Undefined | ts4.TypeFlags.Never)) : checker.isTypeAssignableTo(result, expectedResult);
|
|
5044
|
+
if (result.flags & ts4.TypeFlags.Any || !resultMatches)
|
|
4900
5045
|
report(
|
|
4901
5046
|
impl,
|
|
4902
5047
|
`producer method ${expectedMethod.name} result must agree with its synchronous Contract signature`
|
|
4903
5048
|
);
|
|
4904
5049
|
for (const [i2, parameter] of provided.parameters.entries()) {
|
|
4905
5050
|
const declaration2 = parameter.valueDeclaration;
|
|
4906
|
-
if (declaration2 &&
|
|
5051
|
+
if (declaration2 && ts4.isParameter(declaration2) && declaration2.dotDotDotToken) {
|
|
4907
5052
|
report(
|
|
4908
5053
|
impl,
|
|
4909
5054
|
`producer method ${expectedMethod.name} signature cannot use rest parameters`
|
|
@@ -4916,7 +5061,7 @@ function checkInteropCalls(program, paths, publishes, generatedPath, pluginDir,
|
|
|
4916
5061
|
);
|
|
4917
5062
|
const contractParameter = required.parameters[i2];
|
|
4918
5063
|
if (!contractParameter) {
|
|
4919
|
-
if (!(parameter.flags &
|
|
5064
|
+
if (!(parameter.flags & ts4.SymbolFlags.Optional) && !(declaration2 && ts4.isParameter(declaration2) && (declaration2.questionToken || declaration2.initializer)))
|
|
4920
5065
|
report(
|
|
4921
5066
|
impl,
|
|
4922
5067
|
`producer method ${expectedMethod.name} requires an undeclared input`
|
|
@@ -4927,9 +5072,9 @@ function checkInteropCalls(program, paths, publishes, generatedPath, pluginDir,
|
|
|
4927
5072
|
impl
|
|
4928
5073
|
);
|
|
4929
5074
|
const variants = requiredInput.isUnion() ? requiredInput.types : [requiredInput];
|
|
4930
|
-
const hasDefault = declaration2 &&
|
|
5075
|
+
const hasDefault = declaration2 && ts4.isParameter(declaration2) && declaration2.initializer;
|
|
4931
5076
|
if (!variants.every(
|
|
4932
|
-
(type) => hasDefault && !!(type.flags &
|
|
5077
|
+
(type) => hasDefault && !!(type.flags & ts4.TypeFlags.Undefined) || checker.isTypeAssignableTo(type, input)
|
|
4933
5078
|
))
|
|
4934
5079
|
report(
|
|
4935
5080
|
impl,
|
|
@@ -4944,7 +5089,7 @@ function checkInteropCalls(program, paths, publishes, generatedPath, pluginDir,
|
|
|
4944
5089
|
}
|
|
4945
5090
|
}
|
|
4946
5091
|
}
|
|
4947
|
-
|
|
5092
|
+
ts4.forEachChild(node, visit);
|
|
4948
5093
|
};
|
|
4949
5094
|
visit(sf);
|
|
4950
5095
|
}
|
|
@@ -4953,7 +5098,7 @@ function checkInteropCalls(program, paths, publishes, generatedPath, pluginDir,
|
|
|
4953
5098
|
|
|
4954
5099
|
// src/publishes.ts
|
|
4955
5100
|
import { createHash as createHash3 } from "node:crypto";
|
|
4956
|
-
import { readFileSync as
|
|
5101
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
4957
5102
|
function expandPublishes(authored, pkgName, pkgVersion) {
|
|
4958
5103
|
if (authored === void 0 || authored === null) return {};
|
|
4959
5104
|
if (typeof authored === "string") {
|
|
@@ -4977,7 +5122,7 @@ function expandPublishes(authored, pkgName, pkgVersion) {
|
|
|
4977
5122
|
return out;
|
|
4978
5123
|
}
|
|
4979
5124
|
function hashContract(typesPath) {
|
|
4980
|
-
return createHash3("sha256").update(
|
|
5125
|
+
return createHash3("sha256").update(readFileSync4(typesPath)).digest("hex");
|
|
4981
5126
|
}
|
|
4982
5127
|
var CONCRETE_SEMVER = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
4983
5128
|
function isConcreteVersion(v) {
|
|
@@ -5015,28 +5160,28 @@ function derivePublishes(authored, pkgName, pkgVersion, typesPath) {
|
|
|
5015
5160
|
// src/typecheck/typecheck.ts
|
|
5016
5161
|
import {
|
|
5017
5162
|
mkdirSync,
|
|
5018
|
-
existsSync as
|
|
5019
|
-
readdirSync as
|
|
5020
|
-
readFileSync as
|
|
5163
|
+
existsSync as existsSync8,
|
|
5164
|
+
readdirSync as readdirSync3,
|
|
5165
|
+
readFileSync as readFileSync9,
|
|
5021
5166
|
writeFileSync,
|
|
5022
5167
|
rmSync,
|
|
5023
5168
|
mkdtempSync
|
|
5024
5169
|
} from "node:fs";
|
|
5025
|
-
import { join as
|
|
5170
|
+
import { join as join9, resolve as resolve8, dirname as dirname3 } from "node:path";
|
|
5026
5171
|
import { tmpdir } from "node:os";
|
|
5027
5172
|
|
|
5028
5173
|
// src/packages-resolve.ts
|
|
5029
|
-
import { existsSync as
|
|
5030
|
-
import { dirname, join as
|
|
5174
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
5175
|
+
import { dirname, join as join3, resolve as resolve3 } from "node:path";
|
|
5031
5176
|
import { fileURLToPath } from "node:url";
|
|
5032
5177
|
function isPackagesDir(dir) {
|
|
5033
5178
|
const abs = resolve3(dir);
|
|
5034
|
-
return
|
|
5179
|
+
return existsSync3(join3(abs, "sdk", "globals.d.ts")) || existsSync3(join3(abs, "sdk", "entity.d.ts"));
|
|
5035
5180
|
}
|
|
5036
5181
|
function findPackagesDirNearCli(fromCliUrl = import.meta.url) {
|
|
5037
5182
|
const start = dirname(fileURLToPath(fromCliUrl));
|
|
5038
5183
|
for (const rel of ["../..", "../../.."]) {
|
|
5039
|
-
const candidate =
|
|
5184
|
+
const candidate = join3(start, rel);
|
|
5040
5185
|
if (isPackagesDir(candidate)) return resolve3(candidate);
|
|
5041
5186
|
}
|
|
5042
5187
|
return void 0;
|
|
@@ -5060,7 +5205,7 @@ function resolvePackagesDir(opts) {
|
|
|
5060
5205
|
const nearCli = findPackagesDirNearCli(opts?.fromCliUrl);
|
|
5061
5206
|
if (nearCli) return nearCli;
|
|
5062
5207
|
if (opts?.pluginDir) {
|
|
5063
|
-
const nm =
|
|
5208
|
+
const nm = join3(resolve3(opts.pluginDir), "node_modules", "@s2script");
|
|
5064
5209
|
if (isPackagesDir(nm)) return nm;
|
|
5065
5210
|
}
|
|
5066
5211
|
throw new Error(
|
|
@@ -5069,18 +5214,18 @@ function resolvePackagesDir(opts) {
|
|
|
5069
5214
|
}
|
|
5070
5215
|
|
|
5071
5216
|
// src/contracts.ts
|
|
5072
|
-
import { existsSync as
|
|
5073
|
-
import { join as
|
|
5217
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
5218
|
+
import { join as join4 } from "node:path";
|
|
5074
5219
|
function localContractPath(pluginDir, dep) {
|
|
5075
5220
|
const segs = dep.split("/");
|
|
5076
5221
|
if (segs.some((s) => s === "" || s === "." || s === "..")) return null;
|
|
5077
|
-
const p =
|
|
5078
|
-
return
|
|
5222
|
+
const p = join4(pluginDir, ".s2script", "types", ...segs, "index.d.ts");
|
|
5223
|
+
return existsSync4(p) ? p : null;
|
|
5079
5224
|
}
|
|
5080
5225
|
|
|
5081
5226
|
// src/workspace/siblings.ts
|
|
5082
|
-
import { readFileSync as
|
|
5083
|
-
import { join as
|
|
5227
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
5228
|
+
import { join as join7, relative as relative2, resolve as resolve6 } from "node:path";
|
|
5084
5229
|
|
|
5085
5230
|
// src/workspace/glob.ts
|
|
5086
5231
|
function toPosix(p) {
|
|
@@ -5113,11 +5258,11 @@ function matchGlob(pattern, path2) {
|
|
|
5113
5258
|
}
|
|
5114
5259
|
|
|
5115
5260
|
// src/workspace/workspace.ts
|
|
5116
|
-
import { existsSync as
|
|
5117
|
-
import { dirname as dirname2, join as
|
|
5261
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5, readdirSync as readdirSync2, statSync as statSync2 } from "node:fs";
|
|
5262
|
+
import { dirname as dirname2, join as join5, resolve as resolve4 } from "node:path";
|
|
5118
5263
|
function readPackageJson(path2) {
|
|
5119
5264
|
try {
|
|
5120
|
-
return JSON.parse(
|
|
5265
|
+
return JSON.parse(readFileSync5(path2, "utf8"));
|
|
5121
5266
|
} catch (e) {
|
|
5122
5267
|
throw new Error(`cannot read ${path2}: ${e.message}`);
|
|
5123
5268
|
}
|
|
@@ -5126,7 +5271,7 @@ var MARKER_TEXT = /"s2script"[\s\S]*"workspace"\s*:/;
|
|
|
5126
5271
|
function carriesWorkspaceMarker(pkgPath) {
|
|
5127
5272
|
let text3;
|
|
5128
5273
|
try {
|
|
5129
|
-
text3 =
|
|
5274
|
+
text3 = readFileSync5(pkgPath, "utf8");
|
|
5130
5275
|
} catch {
|
|
5131
5276
|
return false;
|
|
5132
5277
|
}
|
|
@@ -5140,7 +5285,7 @@ function carriesWorkspaceMarker(pkgPath) {
|
|
|
5140
5285
|
function findWorkspaceRoot(from) {
|
|
5141
5286
|
let dir = resolve4(from);
|
|
5142
5287
|
for (; ; ) {
|
|
5143
|
-
if (carriesWorkspaceMarker(
|
|
5288
|
+
if (carriesWorkspaceMarker(join5(dir, "package.json"))) return dir;
|
|
5144
5289
|
const parent = dirname2(dir);
|
|
5145
5290
|
if (parent === dir) return null;
|
|
5146
5291
|
dir = parent;
|
|
@@ -5148,7 +5293,7 @@ function findWorkspaceRoot(from) {
|
|
|
5148
5293
|
}
|
|
5149
5294
|
function isDir(path2) {
|
|
5150
5295
|
try {
|
|
5151
|
-
return
|
|
5296
|
+
return statSync2(path2).isDirectory();
|
|
5152
5297
|
} catch {
|
|
5153
5298
|
return false;
|
|
5154
5299
|
}
|
|
@@ -5156,11 +5301,11 @@ function isDir(path2) {
|
|
|
5156
5301
|
function subdirs(dir) {
|
|
5157
5302
|
let entries;
|
|
5158
5303
|
try {
|
|
5159
|
-
entries =
|
|
5304
|
+
entries = readdirSync2(dir, { withFileTypes: true });
|
|
5160
5305
|
} catch {
|
|
5161
5306
|
return [];
|
|
5162
5307
|
}
|
|
5163
|
-
return entries.filter((e) => e.name !== "node_modules" && !e.name.startsWith(".")).filter((e) => e.isDirectory() || e.isSymbolicLink() && isDir(
|
|
5308
|
+
return entries.filter((e) => e.name !== "node_modules" && !e.name.startsWith(".")).filter((e) => e.isDirectory() || e.isSymbolicLink() && isDir(join5(dir, e.name))).map((e) => e.name);
|
|
5164
5309
|
}
|
|
5165
5310
|
function joinRel(rel, name) {
|
|
5166
5311
|
return rel === "" ? name : `${rel}/${name}`;
|
|
@@ -5174,7 +5319,7 @@ function expandDirGlob(root, pattern) {
|
|
|
5174
5319
|
return;
|
|
5175
5320
|
}
|
|
5176
5321
|
const head = segments[index];
|
|
5177
|
-
const here = rel === "" ? root :
|
|
5322
|
+
const here = rel === "" ? root : join5(root, rel);
|
|
5178
5323
|
if (head === "**") {
|
|
5179
5324
|
walk(index + 1, rel);
|
|
5180
5325
|
for (const name of subdirs(here)) walk(index, joinRel(rel, name));
|
|
@@ -5182,7 +5327,7 @@ function expandDirGlob(root, pattern) {
|
|
|
5182
5327
|
}
|
|
5183
5328
|
if (!head.includes("*")) {
|
|
5184
5329
|
const next = joinRel(rel, head);
|
|
5185
|
-
if (isDir(
|
|
5330
|
+
if (isDir(join5(root, next))) walk(index + 1, next);
|
|
5186
5331
|
return;
|
|
5187
5332
|
}
|
|
5188
5333
|
for (const name of subdirs(here)) {
|
|
@@ -5193,11 +5338,11 @@ function expandDirGlob(root, pattern) {
|
|
|
5193
5338
|
return [...out].sort();
|
|
5194
5339
|
}
|
|
5195
5340
|
function pnpmWorkspaceGlobs(root) {
|
|
5196
|
-
const path2 =
|
|
5197
|
-
if (!
|
|
5341
|
+
const path2 = join5(root, "pnpm-workspace.yaml");
|
|
5342
|
+
if (!existsSync5(path2)) return [];
|
|
5198
5343
|
let body;
|
|
5199
5344
|
try {
|
|
5200
|
-
body =
|
|
5345
|
+
body = readFileSync5(path2, "utf8");
|
|
5201
5346
|
} catch {
|
|
5202
5347
|
return [];
|
|
5203
5348
|
}
|
|
@@ -5239,7 +5384,7 @@ function loadWorkspace(root) {
|
|
|
5239
5384
|
}
|
|
5240
5385
|
function readWorkspace(root) {
|
|
5241
5386
|
const absRoot = resolve4(root);
|
|
5242
|
-
const pkg = readPackageJson(
|
|
5387
|
+
const pkg = readPackageJson(join5(absRoot, "package.json"));
|
|
5243
5388
|
const marker = pkg.s2script?.workspace;
|
|
5244
5389
|
if (marker === void 0) {
|
|
5245
5390
|
throw new Error(
|
|
@@ -5264,9 +5409,9 @@ function readWorkspace(root) {
|
|
|
5264
5409
|
for (const rel of expandDirGlob(absRoot, glob)) candidates.add(rel);
|
|
5265
5410
|
}
|
|
5266
5411
|
for (const rel of [...candidates].sort()) {
|
|
5267
|
-
const dir =
|
|
5268
|
-
const pkgPath =
|
|
5269
|
-
if (!
|
|
5412
|
+
const dir = join5(absRoot, rel);
|
|
5413
|
+
const pkgPath = join5(dir, "package.json");
|
|
5414
|
+
if (!existsSync5(pkgPath)) continue;
|
|
5270
5415
|
pluginDirs.add(rel);
|
|
5271
5416
|
let pluginPkg;
|
|
5272
5417
|
try {
|
|
@@ -5315,9 +5460,9 @@ function readWorkspace(root) {
|
|
|
5315
5460
|
const libs = [];
|
|
5316
5461
|
for (const rel of [...memberDirs].sort()) {
|
|
5317
5462
|
if (pluginDirs.has(rel)) continue;
|
|
5318
|
-
const dir =
|
|
5319
|
-
const pkgPath =
|
|
5320
|
-
if (!
|
|
5463
|
+
const dir = join5(absRoot, rel);
|
|
5464
|
+
const pkgPath = join5(dir, "package.json");
|
|
5465
|
+
if (!existsSync5(pkgPath)) continue;
|
|
5321
5466
|
let libPkg;
|
|
5322
5467
|
try {
|
|
5323
5468
|
libPkg = readPackageJson(pkgPath);
|
|
@@ -5383,8 +5528,8 @@ function ambiguityProblem(iface, publishers) {
|
|
|
5383
5528
|
}
|
|
5384
5529
|
|
|
5385
5530
|
// src/publish-gate.ts
|
|
5386
|
-
import { existsSync as
|
|
5387
|
-
import { join as
|
|
5531
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6, statSync as statSync3 } from "node:fs";
|
|
5532
|
+
import { join as join6, resolve as resolve5 } from "node:path";
|
|
5388
5533
|
function hasPublishes(publishes) {
|
|
5389
5534
|
if (publishes == null) return false;
|
|
5390
5535
|
if (typeof publishes === "string") return publishes.trim().length > 0;
|
|
@@ -5410,14 +5555,14 @@ function assertPublishesTypes(pkg, pluginDir) {
|
|
|
5410
5555
|
};
|
|
5411
5556
|
}
|
|
5412
5557
|
const typesPath = resolve5(pluginDir, typesRel);
|
|
5413
|
-
if (!
|
|
5558
|
+
if (!existsSync6(typesPath)) {
|
|
5414
5559
|
return { ok: false, error: `types file not found: ${typesRel}` };
|
|
5415
5560
|
}
|
|
5416
|
-
const st =
|
|
5561
|
+
const st = statSync3(typesPath);
|
|
5417
5562
|
if (!st.isFile() || st.size === 0) {
|
|
5418
5563
|
return { ok: false, error: `types file is empty or not a file: ${typesRel}` };
|
|
5419
5564
|
}
|
|
5420
|
-
const body =
|
|
5565
|
+
const body = readFileSync6(typesPath, "utf8").trim();
|
|
5421
5566
|
if (!body) {
|
|
5422
5567
|
return { ok: false, error: `types file is empty: ${typesRel}` };
|
|
5423
5568
|
}
|
|
@@ -5426,14 +5571,14 @@ function assertPublishesTypes(pkg, pluginDir) {
|
|
|
5426
5571
|
|
|
5427
5572
|
// src/workspace/siblings.ts
|
|
5428
5573
|
function isWorkspaceMemberDir(root, rootPkg, dir) {
|
|
5429
|
-
const rel = toPosix(
|
|
5574
|
+
const rel = toPosix(relative2(root, dir));
|
|
5430
5575
|
if (rel === "" || rel.startsWith("..")) return false;
|
|
5431
5576
|
const globs = [...workspaceGlobs(rootPkg.workspaces), ...pnpmWorkspaceGlobs(root)];
|
|
5432
5577
|
return globs.some((g) => matchGlob(g, rel));
|
|
5433
5578
|
}
|
|
5434
5579
|
function shadowedCopyWarning(pluginDir, dep) {
|
|
5435
5580
|
const copy = localContractPath(pluginDir, dep);
|
|
5436
|
-
const where2 = copy === null ?
|
|
5581
|
+
const where2 = copy === null ? join7(".s2script", "types", dep, "index.d.ts") : relative2(pluginDir, copy);
|
|
5437
5582
|
return `WARN: ${dep} resolves to a workspace sibling, so the verified copy at ${toPosix(where2)} is IGNORED and can be deleted \u2014 the sibling's own contract is what this build typechecks and hashes`;
|
|
5438
5583
|
}
|
|
5439
5584
|
function resolveSiblingContracts(pluginDir, deps) {
|
|
@@ -5443,13 +5588,13 @@ function resolveSiblingContracts(pluginDir, deps) {
|
|
|
5443
5588
|
const absDir = resolve6(pluginDir);
|
|
5444
5589
|
const root = findWorkspaceRoot(absDir);
|
|
5445
5590
|
if (root === null) return { siblings, shadowedCopies };
|
|
5446
|
-
const rootPkg = JSON.parse(
|
|
5591
|
+
const rootPkg = JSON.parse(readFileSync7(join7(root, "package.json"), "utf8"));
|
|
5447
5592
|
if (!isWorkspaceMemberDir(root, rootPkg, absDir)) return { siblings, shadowedCopies };
|
|
5448
5593
|
const scan = scanWorkspace(root);
|
|
5449
5594
|
const ws = scan.workspace;
|
|
5450
5595
|
const { producers, ambiguous, byPlugin } = indexInterfaces(ws.plugins);
|
|
5451
5596
|
const self = ws.plugins.find((p) => resolve6(p.dir) === absDir);
|
|
5452
|
-
const label = self?.name ?? toPosix(
|
|
5597
|
+
const label = self?.name ?? toPosix(relative2(root, absDir));
|
|
5453
5598
|
const unread = scan.problems ?? [];
|
|
5454
5599
|
const problems = [];
|
|
5455
5600
|
for (const dep of deps) {
|
|
@@ -5497,8 +5642,8 @@ function resolveSiblingContracts(pluginDir, deps) {
|
|
|
5497
5642
|
}
|
|
5498
5643
|
|
|
5499
5644
|
// src/libraries.ts
|
|
5500
|
-
import { existsSync as
|
|
5501
|
-
import { join as
|
|
5645
|
+
import { existsSync as existsSync7, readFileSync as readFileSync8 } from "node:fs";
|
|
5646
|
+
import { join as join8, resolve as resolve7 } from "node:path";
|
|
5502
5647
|
function packageKind(pkg) {
|
|
5503
5648
|
const k = pkg.s2script?.kind ?? "plugin";
|
|
5504
5649
|
if (k !== "plugin" && k !== "library") {
|
|
@@ -5507,13 +5652,13 @@ function packageKind(pkg) {
|
|
|
5507
5652
|
return k;
|
|
5508
5653
|
}
|
|
5509
5654
|
function librariesRoot(pluginDir) {
|
|
5510
|
-
return
|
|
5655
|
+
return join8(pluginDir, ".s2script", "libs");
|
|
5511
5656
|
}
|
|
5512
5657
|
function localLibraryDir(pluginDir, name) {
|
|
5513
5658
|
const segs = name.split("/");
|
|
5514
5659
|
if (segs.some((s) => s === "" || s === "." || s === "..")) return null;
|
|
5515
|
-
const p =
|
|
5516
|
-
return
|
|
5660
|
+
const p = join8(librariesRoot(pluginDir), ...segs);
|
|
5661
|
+
return existsSync7(join8(p, "index.d.ts")) ? p : null;
|
|
5517
5662
|
}
|
|
5518
5663
|
function resolveLibrarySibling(pluginDir, name) {
|
|
5519
5664
|
const absDir = resolve7(pluginDir);
|
|
@@ -5552,7 +5697,7 @@ function resolveLibrarySibling(pluginDir, name) {
|
|
|
5552
5697
|
);
|
|
5553
5698
|
}
|
|
5554
5699
|
const typesPath = resolve7(lib.dir, typesRel);
|
|
5555
|
-
if (!
|
|
5700
|
+
if (!existsSync7(typesPath)) {
|
|
5556
5701
|
throw new Error(
|
|
5557
5702
|
`library ${name} (workspace sibling at ${lib.relDir}) types file not found: ${typesRel}`
|
|
5558
5703
|
);
|
|
@@ -5567,11 +5712,11 @@ function resolveLibraries(pluginDir, declared) {
|
|
|
5567
5712
|
for (const name of Object.keys(declared)) {
|
|
5568
5713
|
const dir = localLibraryDir(pluginDir, name);
|
|
5569
5714
|
if (dir !== null) {
|
|
5570
|
-
paths[name] = [
|
|
5715
|
+
paths[name] = [join8(dir, "index.d.ts")];
|
|
5571
5716
|
let version = "0.0.0";
|
|
5572
5717
|
let apiVersion = "1.x";
|
|
5573
5718
|
try {
|
|
5574
|
-
const m = JSON.parse(
|
|
5719
|
+
const m = JSON.parse(readFileSync8(join8(dir, "package.json"), "utf8"));
|
|
5575
5720
|
if (typeof m.version === "string") version = m.version;
|
|
5576
5721
|
if (typeof m.s2script?.apiVersion === "string") apiVersion = m.s2script.apiVersion;
|
|
5577
5722
|
} catch {
|
|
@@ -5622,27 +5767,27 @@ function assertLibrariesResolved(pluginDir, declared, sdkApiVersion) {
|
|
|
5622
5767
|
|
|
5623
5768
|
// src/typecheck/typecheck.ts
|
|
5624
5769
|
function localDeclarationFiles(pluginDir) {
|
|
5625
|
-
const srcDir =
|
|
5626
|
-
if (!
|
|
5627
|
-
return
|
|
5770
|
+
const srcDir = join9(pluginDir, "src");
|
|
5771
|
+
if (!existsSync8(srcDir)) return [];
|
|
5772
|
+
return readdirSync3(srcDir).filter((f) => f.endsWith(".d.ts")).map((f) => join9(srcDir, f));
|
|
5628
5773
|
}
|
|
5629
5774
|
function gamedataDeclarations(pluginDir, pkg) {
|
|
5630
5775
|
const data = loadPluginGamedata(pluginDir, pkg) ?? {};
|
|
5631
5776
|
return /* @__PURE__ */ new Map([
|
|
5632
|
-
[
|
|
5633
|
-
[
|
|
5777
|
+
[join9(pluginDir, ".s2script", "gamedata.d.ts"), generateGamedataTypes(data)],
|
|
5778
|
+
[join9(pluginDir, ".s2script", "hooks.d.ts"), generateHookTypes(data)]
|
|
5634
5779
|
]);
|
|
5635
5780
|
}
|
|
5636
5781
|
function gamePackageDeclarationFiles(pkg, packagesDir) {
|
|
5637
5782
|
const deps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
5638
5783
|
if (!("@s2script/cs2" in deps)) return [];
|
|
5639
|
-
const hooks =
|
|
5640
|
-
return
|
|
5784
|
+
const hooks = join9(packagesDir, "cs2", "hooks.generated.d.ts");
|
|
5785
|
+
return existsSync8(hooks) ? [hooks] : [];
|
|
5641
5786
|
}
|
|
5642
5787
|
function declaredModules(dtsFiles) {
|
|
5643
5788
|
const out = /* @__PURE__ */ new Set();
|
|
5644
5789
|
for (const f of dtsFiles) {
|
|
5645
|
-
const body =
|
|
5790
|
+
const body = readFileSync9(f, "utf8");
|
|
5646
5791
|
for (const m of body.matchAll(/declare\s+module\s+["']([^"']+)["']/g))
|
|
5647
5792
|
out.add(m[1]);
|
|
5648
5793
|
}
|
|
@@ -5651,12 +5796,12 @@ function declaredModules(dtsFiles) {
|
|
|
5651
5796
|
function typecheckPlugin(pluginDir, opts) {
|
|
5652
5797
|
const absDir = resolve8(pluginDir);
|
|
5653
5798
|
const packagesDir = opts?.packagesDir ? resolve8(opts.packagesDir) : resolvePackagesDir({ pluginDir: absDir });
|
|
5654
|
-
const pkg = JSON.parse(
|
|
5799
|
+
const pkg = JSON.parse(readFileSync9(join9(absDir, "package.json"), "utf8"));
|
|
5655
5800
|
const s2 = pkg.s2script ?? {};
|
|
5656
5801
|
const entryRel = s2.main ?? pkg.main;
|
|
5657
5802
|
if (!entryRel)
|
|
5658
5803
|
throw new Error(
|
|
5659
|
-
`typecheckPlugin: no entry point in ${
|
|
5804
|
+
`typecheckPlugin: no entry point in ${join9(absDir, "package.json")}`
|
|
5660
5805
|
);
|
|
5661
5806
|
const entry = resolve8(absDir, entryRel);
|
|
5662
5807
|
const isAlwaysResolved = (d) => d === "@s2script/sdk" || d.startsWith("@s2script/sdk/") || d === "@s2script/cs2" || d.startsWith("@s2script/cs2/");
|
|
@@ -5677,6 +5822,11 @@ function typecheckPlugin(pluginDir, opts) {
|
|
|
5677
5822
|
const p = localContractPath(absDir, d);
|
|
5678
5823
|
if (p !== null) contractPaths[d] = [p];
|
|
5679
5824
|
}
|
|
5825
|
+
const extensionPaths = /* @__PURE__ */ Object.create(null);
|
|
5826
|
+
for (const name of Object.keys(s2.extensions ?? {})) {
|
|
5827
|
+
const local = join9(absDir, ".s2script", "extensions", name, "index.d.ts");
|
|
5828
|
+
if (existsSync8(local)) extensionPaths[name] = [local];
|
|
5829
|
+
}
|
|
5680
5830
|
const protocol2 = s2.interfaceProtocol === 2;
|
|
5681
5831
|
const authoritativePaths = Object.fromEntries(
|
|
5682
5832
|
Object.entries(contractPaths).map(([name, paths]) => [name, paths[0]])
|
|
@@ -5699,9 +5849,9 @@ function typecheckPlugin(pluginDir, opts) {
|
|
|
5699
5849
|
for (const [name, path2] of Object.entries(authoritativePaths)) {
|
|
5700
5850
|
interfaceContracts[name] = extractContract(path2, packagesDir);
|
|
5701
5851
|
if (!siblings.has(name) && !ownNames.has(name)) {
|
|
5702
|
-
const receipt =
|
|
5703
|
-
if (
|
|
5704
|
-
const published = JSON.parse(
|
|
5852
|
+
const receipt = join9(dirname3(path2), "package.json");
|
|
5853
|
+
if (existsSync8(receipt)) {
|
|
5854
|
+
const published = JSON.parse(readFileSync9(receipt, "utf8")).s2script?.publishes?.[name];
|
|
5705
5855
|
if (!published || published.typesSha256 !== hashContract(path2) || published.contract?.sha256 !== interfaceContracts[name].sha256)
|
|
5706
5856
|
throw new Error(
|
|
5707
5857
|
`InterfaceContractError: ${name} verified copy hash drift; run s2s add`
|
|
@@ -5737,7 +5887,7 @@ function typecheckPlugin(pluginDir, opts) {
|
|
|
5737
5887
|
const options = {
|
|
5738
5888
|
// Accept explicit `.ts` import extensions (node type-stripping requires them for source-to-source
|
|
5739
5889
|
// imports; esbuild strips them at bundle time). Backward-compatible — extensionless imports still resolve.
|
|
5740
|
-
...sharedProgramOptions(
|
|
5890
|
+
...sharedProgramOptions(ts5),
|
|
5741
5891
|
baseUrl: packagesDir,
|
|
5742
5892
|
paths: {
|
|
5743
5893
|
// Builtins: the root barrel `@s2script/sdk` → packages/sdk/index.d.ts; subpaths
|
|
@@ -5753,28 +5903,29 @@ function typecheckPlugin(pluginDir, opts) {
|
|
|
5753
5903
|
"@s2script/cs2/*": ["cs2/*.d.ts"],
|
|
5754
5904
|
"@s2script/*": ["*/index.d.ts"],
|
|
5755
5905
|
...contractPaths,
|
|
5756
|
-
...libraryPaths
|
|
5906
|
+
...libraryPaths,
|
|
5907
|
+
...extensionPaths
|
|
5757
5908
|
}
|
|
5758
5909
|
};
|
|
5759
5910
|
const virtualDeclarations = gamedataDeclarations(absDir, pkg);
|
|
5760
5911
|
const engineFunctions = loadEngineFunctions(absDir, pkg.name);
|
|
5761
|
-
virtualDeclarations.set(
|
|
5912
|
+
virtualDeclarations.set(join9(absDir, ".s2script", "engine-functions.d.ts"), emitEngineFunctionTypes(engineFunctions));
|
|
5762
5913
|
const rootNames = [
|
|
5763
5914
|
entry,
|
|
5764
|
-
|
|
5915
|
+
join9(packagesDir, "sdk", "globals.d.ts"),
|
|
5765
5916
|
...localDts,
|
|
5766
5917
|
...virtualDeclarations.keys(),
|
|
5767
5918
|
...gamePackageDeclarationFiles(pkg, packagesDir)
|
|
5768
5919
|
];
|
|
5769
|
-
const tmp = mkdtempSync(
|
|
5920
|
+
const tmp = mkdtempSync(join9(tmpdir(), "s2tc-"));
|
|
5770
5921
|
try {
|
|
5771
|
-
const generatedPath =
|
|
5922
|
+
const generatedPath = join9(absDir, ".s2script", "interfaces.d.ts");
|
|
5772
5923
|
rmSync(generatedPath, { force: true });
|
|
5773
5924
|
if (protocol2) {
|
|
5774
|
-
mkdirSync(
|
|
5925
|
+
mkdirSync(join9(absDir, ".s2script"), { recursive: true });
|
|
5775
5926
|
let moduleId = 0;
|
|
5776
5927
|
for (const name of allDeclaredDeps) {
|
|
5777
|
-
const path2 = authoritativePaths[name], wrapper =
|
|
5928
|
+
const path2 = authoritativePaths[name], wrapper = join9(tmp, `contract-${moduleId++}.d.ts`);
|
|
5778
5929
|
writeFileSync(
|
|
5779
5930
|
wrapper,
|
|
5780
5931
|
`import type {Contract} from ${JSON.stringify(
|
|
@@ -5801,14 +5952,14 @@ export declare const on: import("@s2script/sdk/interfaces").TypedInterfaceHandle
|
|
|
5801
5952
|
rootNames.push(generatedPath);
|
|
5802
5953
|
}
|
|
5803
5954
|
if (deps.length && !protocol2) {
|
|
5804
|
-
const stub =
|
|
5955
|
+
const stub = join9(tmp, "ambient.d.ts");
|
|
5805
5956
|
writeFileSync(
|
|
5806
5957
|
stub,
|
|
5807
5958
|
deps.map((d) => `declare module ${JSON.stringify(d)};`).join("\n") + "\n"
|
|
5808
5959
|
);
|
|
5809
5960
|
rootNames.push(stub);
|
|
5810
5961
|
}
|
|
5811
|
-
const host =
|
|
5962
|
+
const host = ts5.createCompilerHost(options);
|
|
5812
5963
|
const originalReadFile = host.readFile.bind(host);
|
|
5813
5964
|
const originalFileExists = host.fileExists.bind(host);
|
|
5814
5965
|
host.readFile = (file) => virtualDeclarations.get(resolve8(file)) ?? originalReadFile(file);
|
|
@@ -5816,9 +5967,9 @@ export declare const on: import("@s2script/sdk/interfaces").TypedInterfaceHandle
|
|
|
5816
5967
|
const originalGetSourceFile = host.getSourceFile.bind(host);
|
|
5817
5968
|
host.getSourceFile = (file, languageVersion, onError, shouldCreateNewSourceFile) => {
|
|
5818
5969
|
const text3 = virtualDeclarations.get(resolve8(file));
|
|
5819
|
-
return text3 === void 0 ? originalGetSourceFile(file, languageVersion, onError, shouldCreateNewSourceFile) :
|
|
5970
|
+
return text3 === void 0 ? originalGetSourceFile(file, languageVersion, onError, shouldCreateNewSourceFile) : ts5.createSourceFile(file, text3, languageVersion);
|
|
5820
5971
|
};
|
|
5821
|
-
const program =
|
|
5972
|
+
const program = ts5.createProgram(rootNames, options, host);
|
|
5822
5973
|
const diags = [
|
|
5823
5974
|
...program.getSyntacticDiagnostics(),
|
|
5824
5975
|
...program.getSemanticDiagnostics(),
|
|
@@ -5846,7 +5997,7 @@ export declare const on: import("@s2script/sdk/interfaces").TypedInterfaceHandle
|
|
|
5846
5997
|
line,
|
|
5847
5998
|
col,
|
|
5848
5999
|
code: d.code,
|
|
5849
|
-
message:
|
|
6000
|
+
message: ts5.flattenDiagnosticMessageText(d.messageText, "\n")
|
|
5850
6001
|
};
|
|
5851
6002
|
});
|
|
5852
6003
|
return {
|
|
@@ -5967,12 +6118,12 @@ var STAMPED_API_VERSION = `${HOST_API_VERSION_MAJOR}.x`;
|
|
|
5967
6118
|
|
|
5968
6119
|
// src/npm-deps-gate.ts
|
|
5969
6120
|
import { lstatSync, realpathSync } from "node:fs";
|
|
5970
|
-
import { dirname as dirname4, join as
|
|
6121
|
+
import { dirname as dirname4, join as join10, resolve as resolve9, sep as sep2 } from "node:path";
|
|
5971
6122
|
function findInNodeModules(startDir, dep) {
|
|
5972
6123
|
const segs = dep.split("/");
|
|
5973
6124
|
let dir = resolve9(startDir);
|
|
5974
6125
|
for (; ; ) {
|
|
5975
|
-
const candidate =
|
|
6126
|
+
const candidate = join10(dir, "node_modules", ...segs);
|
|
5976
6127
|
try {
|
|
5977
6128
|
lstatSync(candidate);
|
|
5978
6129
|
return candidate;
|
|
@@ -6013,20 +6164,20 @@ function assertNoNpmRuntimeDeps(pkg, pluginDir) {
|
|
|
6013
6164
|
|
|
6014
6165
|
// src/build-library.ts
|
|
6015
6166
|
import * as esbuild from "esbuild";
|
|
6016
|
-
import { readFileSync as
|
|
6017
|
-
import { resolve as resolve11, join as
|
|
6167
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync10, statSync as statSync4 } from "node:fs";
|
|
6168
|
+
import { resolve as resolve11, join as join12 } from "node:path";
|
|
6018
6169
|
|
|
6019
6170
|
// src/lint/lint.ts
|
|
6020
6171
|
import { ESLint } from "eslint";
|
|
6021
|
-
import { existsSync as
|
|
6022
|
-
import { dirname as dirname5, join as
|
|
6172
|
+
import { existsSync as existsSync9, readdirSync as readdirSync4 } from "node:fs";
|
|
6173
|
+
import { dirname as dirname5, join as join11, resolve as resolve10 } from "node:path";
|
|
6023
6174
|
import s2lint from "@s2script/eslint-plugin";
|
|
6024
6175
|
var CONFIG_FILES = ["eslint.config.js", "eslint.config.mjs", "eslint.config.cjs", "eslint.config.ts"];
|
|
6025
6176
|
function ownConfigDir(pluginDir) {
|
|
6026
6177
|
const stopAt = findWorkspaceRoot(pluginDir);
|
|
6027
6178
|
let dir = pluginDir;
|
|
6028
6179
|
for (; ; ) {
|
|
6029
|
-
if (CONFIG_FILES.some((f) =>
|
|
6180
|
+
if (CONFIG_FILES.some((f) => existsSync9(join11(dir, f)))) return dir;
|
|
6030
6181
|
if (stopAt === null || dir === stopAt) return null;
|
|
6031
6182
|
const parent = dirname5(dir);
|
|
6032
6183
|
if (parent === dir) return null;
|
|
@@ -6036,14 +6187,14 @@ function ownConfigDir(pluginDir) {
|
|
|
6036
6187
|
function collectTsFiles(dir) {
|
|
6037
6188
|
let entries;
|
|
6038
6189
|
try {
|
|
6039
|
-
entries =
|
|
6190
|
+
entries = readdirSync4(dir, { withFileTypes: true });
|
|
6040
6191
|
} catch {
|
|
6041
6192
|
return [];
|
|
6042
6193
|
}
|
|
6043
6194
|
const out = [];
|
|
6044
6195
|
for (const e of entries) {
|
|
6045
6196
|
if (e.name === "node_modules" || e.name.startsWith(".")) continue;
|
|
6046
|
-
const full =
|
|
6197
|
+
const full = join11(dir, e.name);
|
|
6047
6198
|
if (e.isDirectory()) out.push(...collectTsFiles(full));
|
|
6048
6199
|
else if (e.isFile() && e.name.endsWith(".ts") && !e.name.endsWith(".d.ts")) out.push(full);
|
|
6049
6200
|
}
|
|
@@ -6072,8 +6223,8 @@ async function lintPlugin(pluginDir, program) {
|
|
|
6072
6223
|
// src/build-library.ts
|
|
6073
6224
|
async function buildLibrary(dir, packagesDir) {
|
|
6074
6225
|
const absDir = resolve11(dir);
|
|
6075
|
-
const pkgPath =
|
|
6076
|
-
const pkg = JSON.parse(
|
|
6226
|
+
const pkgPath = join12(absDir, "package.json");
|
|
6227
|
+
const pkg = JSON.parse(readFileSync10(pkgPath, "utf8"));
|
|
6077
6228
|
const s2 = pkg.s2script ?? {};
|
|
6078
6229
|
if (s2.pluginDependencies || s2.optionalPluginDependencies) {
|
|
6079
6230
|
throw new Error(
|
|
@@ -6088,7 +6239,7 @@ async function buildLibrary(dir, packagesDir) {
|
|
|
6088
6239
|
throw new Error('a library must set "types" to a .d.ts \u2014 consumers vendor it to typecheck against');
|
|
6089
6240
|
}
|
|
6090
6241
|
const typesPath = resolve11(absDir, typesRel);
|
|
6091
|
-
if (!
|
|
6242
|
+
if (!existsSync10(typesPath) || !statSync4(typesPath).isFile() || statSync4(typesPath).size === 0) {
|
|
6092
6243
|
throw new Error(`types file is missing or empty: ${typesRel}`);
|
|
6093
6244
|
}
|
|
6094
6245
|
assertNoNpmRuntimeDeps(pkg, absDir);
|
|
@@ -6107,7 +6258,7 @@ ${lint.output}`);
|
|
|
6107
6258
|
const entryRelative = s2.main ?? pkg.main;
|
|
6108
6259
|
if (!entryRelative) throw new Error(`buildLibrary: no entry point in ${pkgPath} (set s2script.main or main)`);
|
|
6109
6260
|
const result = await esbuild.build({
|
|
6110
|
-
entryPoints: [
|
|
6261
|
+
entryPoints: [join12(absDir, entryRelative)],
|
|
6111
6262
|
bundle: true,
|
|
6112
6263
|
platform: "neutral",
|
|
6113
6264
|
format: "cjs",
|
|
@@ -6133,15 +6284,15 @@ ${lint.output}`);
|
|
|
6133
6284
|
types: "index.d.ts"
|
|
6134
6285
|
};
|
|
6135
6286
|
const sanitized = String(pkg.name).replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
6136
|
-
const outDir =
|
|
6287
|
+
const outDir = join12(absDir, "dist");
|
|
6137
6288
|
mkdirSync2(outDir, { recursive: true });
|
|
6138
|
-
const outPath =
|
|
6289
|
+
const outPath = join12(outDir, `${sanitized}.s2lib`);
|
|
6139
6290
|
writeFileSync2(
|
|
6140
6291
|
outPath,
|
|
6141
6292
|
zipSync({
|
|
6142
6293
|
"manifest.json": Buffer.from(JSON.stringify(manifest, null, 2)),
|
|
6143
6294
|
"index.js": Buffer.from(result.outputFiles[0].text),
|
|
6144
|
-
"index.d.ts":
|
|
6295
|
+
"index.d.ts": readFileSync10(typesPath)
|
|
6145
6296
|
})
|
|
6146
6297
|
);
|
|
6147
6298
|
return outPath;
|
|
@@ -6150,8 +6301,8 @@ ${lint.output}`);
|
|
|
6150
6301
|
// src/build.ts
|
|
6151
6302
|
async function buildPlugin(dir, packagesDir) {
|
|
6152
6303
|
const absDir = resolve12(dir);
|
|
6153
|
-
const pkgPath =
|
|
6154
|
-
const pkg = JSON.parse(
|
|
6304
|
+
const pkgPath = join13(absDir, "package.json");
|
|
6305
|
+
const pkg = JSON.parse(readFileSync11(pkgPath, "utf8"));
|
|
6155
6306
|
if (packageKind(pkg) === "library") {
|
|
6156
6307
|
throw new Error(`${pkgPath} is s2script.kind="library" \u2014 build it with buildLibrary/buildPackage`);
|
|
6157
6308
|
}
|
|
@@ -6175,6 +6326,17 @@ async function buildPlugin(dir, packagesDir) {
|
|
|
6175
6326
|
);
|
|
6176
6327
|
}
|
|
6177
6328
|
}
|
|
6329
|
+
const extensions = s2.extensions ?? {};
|
|
6330
|
+
for (const name2 of Object.keys(extensions)) {
|
|
6331
|
+
if (pluginDepNames.has(name2) || Object.hasOwn(libraries, name2)) {
|
|
6332
|
+
throw new Error(
|
|
6333
|
+
`${JSON.stringify(name2)} is declared in s2script.extensions and also as a library or plugin dependency \u2014 a native extension is resolved by the host from addons/s2script/extensions/, so it cannot share a name with either`
|
|
6334
|
+
);
|
|
6335
|
+
}
|
|
6336
|
+
if (name2.startsWith("@s2script/sdk")) {
|
|
6337
|
+
throw new Error(`${JSON.stringify(name2)}: s2script.extensions cannot name an @s2script/sdk module`);
|
|
6338
|
+
}
|
|
6339
|
+
}
|
|
6178
6340
|
const librariesResolved = assertLibrariesResolved(absDir, libraries, STAMPED_API_VERSION);
|
|
6179
6341
|
const permissions = Array.isArray(s2.permissions) ? s2.permissions : [];
|
|
6180
6342
|
const gamedata = loadPluginGamedata(absDir, pkg);
|
|
@@ -6187,27 +6349,27 @@ async function buildPlugin(dir, packagesDir) {
|
|
|
6187
6349
|
throw new Error(`remove authored ${permission} from s2script.permissions: gamedata/functions.jsonc derives it automatically`);
|
|
6188
6350
|
}
|
|
6189
6351
|
}
|
|
6190
|
-
mkdirSync3(
|
|
6191
|
-
writeFileSync3(
|
|
6352
|
+
mkdirSync3(join13(absDir, ".s2script"), { recursive: true });
|
|
6353
|
+
writeFileSync3(join13(absDir, ".s2script", "engine-functions.d.ts"), emitEngineFunctionTypes(engineFunctions));
|
|
6192
6354
|
console.log(`engine functions: derived permissions ${derivedFunctions.permissions.join(", ") || "(none)"}`);
|
|
6193
6355
|
for (const f of derivedFunctions.summary.functions) {
|
|
6194
6356
|
if (f.mutates || f.suppresses) console.log(`engine functions: ${f.canonicalId} risks ${[f.mutates ? "mutation" : "", f.suppresses ? "suppression" : ""].filter(Boolean).join(", ")}`);
|
|
6195
6357
|
}
|
|
6196
6358
|
} else {
|
|
6197
|
-
rmSync2(
|
|
6359
|
+
rmSync2(join13(absDir, ".s2script", "engine-functions.d.ts"), { force: true });
|
|
6198
6360
|
}
|
|
6199
6361
|
if (gamedata) {
|
|
6200
|
-
const genDir =
|
|
6362
|
+
const genDir = join13(absDir, ".s2script");
|
|
6201
6363
|
mkdirSync3(genDir, { recursive: true });
|
|
6202
|
-
writeFileSync3(
|
|
6364
|
+
writeFileSync3(join13(genDir, "gamedata.d.ts"), generateGamedataTypes(gamedata));
|
|
6203
6365
|
if (gamedata.hooks && Object.keys(gamedata.hooks).length) {
|
|
6204
|
-
writeFileSync3(
|
|
6366
|
+
writeFileSync3(join13(genDir, "hooks.d.ts"), generateHookTypes(gamedata));
|
|
6205
6367
|
} else {
|
|
6206
|
-
rmSync2(
|
|
6368
|
+
rmSync2(join13(genDir, "hooks.d.ts"), { force: true });
|
|
6207
6369
|
}
|
|
6208
6370
|
} else {
|
|
6209
|
-
rmSync2(
|
|
6210
|
-
rmSync2(
|
|
6371
|
+
rmSync2(join13(absDir, ".s2script", "gamedata.d.ts"), { force: true });
|
|
6372
|
+
rmSync2(join13(absDir, ".s2script", "hooks.d.ts"), { force: true });
|
|
6211
6373
|
}
|
|
6212
6374
|
const declaredDepNames = [
|
|
6213
6375
|
...Object.keys(s2.pluginDependencies ?? {}),
|
|
@@ -6282,6 +6444,13 @@ ${lint.output}`);
|
|
|
6282
6444
|
);
|
|
6283
6445
|
}
|
|
6284
6446
|
}
|
|
6447
|
+
for (const ext2 of Object.keys(extensions)) {
|
|
6448
|
+
if (!scan.importNames.includes(ext2)) {
|
|
6449
|
+
console.warn(
|
|
6450
|
+
`WARN: extension ${JSON.stringify(ext2)} is declared but never imported \u2014 the plugin still refuses to load on a server without it`
|
|
6451
|
+
);
|
|
6452
|
+
}
|
|
6453
|
+
}
|
|
6285
6454
|
const { name, version } = pkg;
|
|
6286
6455
|
if (s2.apiVersion !== void 0) {
|
|
6287
6456
|
console.warn(
|
|
@@ -6292,7 +6461,8 @@ ${lint.output}`);
|
|
|
6292
6461
|
const external = Array.from(/* @__PURE__ */ new Set([
|
|
6293
6462
|
"@s2script/*",
|
|
6294
6463
|
...Object.keys(pluginDependencies),
|
|
6295
|
-
...Object.keys(optionalPluginDependencies)
|
|
6464
|
+
...Object.keys(optionalPluginDependencies),
|
|
6465
|
+
...Object.keys(extensions)
|
|
6296
6466
|
]));
|
|
6297
6467
|
const entryRelative = s2.main ?? pkg.main;
|
|
6298
6468
|
if (!entryRelative) {
|
|
@@ -6300,7 +6470,7 @@ ${lint.output}`);
|
|
|
6300
6470
|
`buildPlugin: no entry point found in ${pkgPath} (set s2script.main or main)`
|
|
6301
6471
|
);
|
|
6302
6472
|
}
|
|
6303
|
-
const entryPoint =
|
|
6473
|
+
const entryPoint = join13(absDir, entryRelative);
|
|
6304
6474
|
const result = await esbuild2.build({
|
|
6305
6475
|
entryPoints: [entryPoint],
|
|
6306
6476
|
bundle: true,
|
|
@@ -6344,6 +6514,7 @@ ${lint.output}`);
|
|
|
6344
6514
|
manifest.interfaceContracts = imports;
|
|
6345
6515
|
}
|
|
6346
6516
|
if (config !== void 0) manifest.config = config;
|
|
6517
|
+
if (Object.keys(extensions).length > 0) manifest.extensions = extensions;
|
|
6347
6518
|
const gamedataPermissions = [
|
|
6348
6519
|
...gamedata?.calls && Object.keys(gamedata.calls).length ? ["engine:calls"] : [],
|
|
6349
6520
|
...gamedata?.hooks && Object.keys(gamedata.hooks).length ? ["engine:hooks"] : []
|
|
@@ -6374,21 +6545,21 @@ ${lint.output}`);
|
|
|
6374
6545
|
if (gamedata) zipFiles["gamedata.json"] = Buffer.from(JSON.stringify(gamedata, null, 2));
|
|
6375
6546
|
if (engineFunctions) zipFiles["engine-functions.json"] = Buffer.from(engineFunctionsArchive(engineFunctions));
|
|
6376
6547
|
if (gate.typesPath !== null && Object.keys(derivedPublishes).length > 0) {
|
|
6377
|
-
const contract =
|
|
6548
|
+
const contract = readFileSync11(gate.typesPath);
|
|
6378
6549
|
for (const iface of Object.keys(derivedPublishes)) {
|
|
6379
6550
|
const safe = iface.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
6380
6551
|
zipFiles[`types/${safe}.d.ts`] = contract;
|
|
6381
6552
|
}
|
|
6382
6553
|
}
|
|
6383
6554
|
const sanitizedId = name.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
6384
|
-
const outDir =
|
|
6555
|
+
const outDir = join13(absDir, "dist");
|
|
6385
6556
|
mkdirSync3(outDir, { recursive: true });
|
|
6386
|
-
const outPath =
|
|
6557
|
+
const outPath = join13(outDir, `${sanitizedId}.s2sp`);
|
|
6387
6558
|
writeFileSync3(outPath, zipSync(zipFiles));
|
|
6388
6559
|
return outPath;
|
|
6389
6560
|
}
|
|
6390
6561
|
async function buildPackage(dir, packagesDir) {
|
|
6391
|
-
const pkg = JSON.parse(
|
|
6562
|
+
const pkg = JSON.parse(readFileSync11(join13(resolve12(dir), "package.json"), "utf8"));
|
|
6392
6563
|
return packageKind(pkg) === "library" ? buildLibrary(dir, packagesDir) : buildPlugin(dir, packagesDir);
|
|
6393
6564
|
}
|
|
6394
6565
|
|
|
@@ -6420,7 +6591,7 @@ function positionals(args, flagsWithValue) {
|
|
|
6420
6591
|
|
|
6421
6592
|
// src/workspace/build-all.ts
|
|
6422
6593
|
import { writeFileSync as writeFileSync4 } from "node:fs";
|
|
6423
|
-
import { join as
|
|
6594
|
+
import { join as join14 } from "node:path";
|
|
6424
6595
|
|
|
6425
6596
|
// src/workspace/graph.ts
|
|
6426
6597
|
function topoOrder(batch, warn = console.warn) {
|
|
@@ -6740,7 +6911,7 @@ function stampWorkspaceVersion(ws, version) {
|
|
|
6740
6911
|
dirty = true;
|
|
6741
6912
|
}
|
|
6742
6913
|
}
|
|
6743
|
-
if (dirty) writeFileSync4(
|
|
6914
|
+
if (dirty) writeFileSync4(join14(p.dir, "package.json"), `${JSON.stringify(next, null, 2)}
|
|
6744
6915
|
`);
|
|
6745
6916
|
}
|
|
6746
6917
|
return result;
|
|
@@ -7884,10 +8055,10 @@ var spinner = ({
|
|
|
7884
8055
|
...I2
|
|
7885
8056
|
} = {}) => {
|
|
7886
8057
|
const u4 = isCI();
|
|
7887
|
-
let M, T, d = false,
|
|
8058
|
+
let M, T, d = false, S4 = false, s = "", p, w = performance.now();
|
|
7888
8059
|
const x = getColumns(n3), k = I2?.styleFrame ?? W, g = (e) => {
|
|
7889
8060
|
const r2 = e > 1 ? O ?? settings.messages.error : G ?? settings.messages.cancel;
|
|
7890
|
-
|
|
8061
|
+
S4 = e === 1, d && (a2(r2, e), S4 && typeof h2 == "function" && h2());
|
|
7891
8062
|
}, f = () => g(2), i2 = () => g(1), A = () => {
|
|
7892
8063
|
process.on("uncaughtExceptionMonitor", f), process.on("unhandledRejection", f), process.on("SIGINT", i2), process.on("SIGTERM", i2), process.on("exit", g), m && m.addEventListener("abort", i2);
|
|
7893
8064
|
}, H = () => {
|
|
@@ -7947,7 +8118,7 @@ var spinner = ({
|
|
|
7947
8118
|
error: (e = "") => a2(e, 2),
|
|
7948
8119
|
clear: () => a2("", 0, true),
|
|
7949
8120
|
get isCancelled() {
|
|
7950
|
-
return
|
|
8121
|
+
return S4;
|
|
7951
8122
|
}
|
|
7952
8123
|
};
|
|
7953
8124
|
};
|
|
@@ -8221,11 +8392,11 @@ async function runWorkspace(argv2, root, interactive, filters, stampVersion) {
|
|
|
8221
8392
|
import { resolve as resolve16 } from "node:path";
|
|
8222
8393
|
|
|
8223
8394
|
// src/registry/deploy.ts
|
|
8224
|
-
import { readdirSync as
|
|
8395
|
+
import { readdirSync as readdirSync6, readFileSync as readFileSync15 } from "node:fs";
|
|
8225
8396
|
import { resolve as resolve15 } from "node:path";
|
|
8226
8397
|
|
|
8227
8398
|
// src/types-pack.ts
|
|
8228
|
-
import { readFileSync as
|
|
8399
|
+
import { readFileSync as readFileSync12 } from "node:fs";
|
|
8229
8400
|
|
|
8230
8401
|
// src/tar.ts
|
|
8231
8402
|
import { gzipSync } from "node:zlib";
|
|
@@ -8281,7 +8452,7 @@ function packTar(files, opts = {}) {
|
|
|
8281
8452
|
|
|
8282
8453
|
// src/types-pack.ts
|
|
8283
8454
|
function packTypesTarball(input) {
|
|
8284
|
-
const dts =
|
|
8455
|
+
const dts = readFileSync12(input.typesPath);
|
|
8285
8456
|
const pkgJson = Buffer.from(
|
|
8286
8457
|
JSON.stringify(
|
|
8287
8458
|
{
|
|
@@ -8306,8 +8477,8 @@ function packTypesTarball(input) {
|
|
|
8306
8477
|
|
|
8307
8478
|
// src/source-pack.ts
|
|
8308
8479
|
var import_ignore = __toESM(require_ignore(), 1);
|
|
8309
|
-
import { readdirSync as
|
|
8310
|
-
import { dirname as dirname6, join as
|
|
8480
|
+
import { readdirSync as readdirSync5, readFileSync as readFileSync13, statSync as statSync5 } from "node:fs";
|
|
8481
|
+
import { dirname as dirname6, join as join15, relative as relative3, resolve as resolve14, sep as sep4 } from "node:path";
|
|
8311
8482
|
|
|
8312
8483
|
// ../../node_modules/balanced-match/dist/esm/index.js
|
|
8313
8484
|
var balanced = (a2, b, str) => {
|
|
@@ -10205,7 +10376,7 @@ function readIgnoreFile(dir) {
|
|
|
10205
10376
|
for (const name of [".npmignore", ".gitignore"]) {
|
|
10206
10377
|
let text3;
|
|
10207
10378
|
try {
|
|
10208
|
-
text3 =
|
|
10379
|
+
text3 = readFileSync13(join15(dir, name), "utf8");
|
|
10209
10380
|
} catch {
|
|
10210
10381
|
continue;
|
|
10211
10382
|
}
|
|
@@ -10216,7 +10387,7 @@ function readIgnoreFile(dir) {
|
|
|
10216
10387
|
function isIgnored(abs, isDir2, rulesets) {
|
|
10217
10388
|
let ignored = false;
|
|
10218
10389
|
for (const { base, rules } of rulesets) {
|
|
10219
|
-
const rel = toPosix2(
|
|
10390
|
+
const rel = toPosix2(relative3(base, abs));
|
|
10220
10391
|
if (!rel || rel.startsWith("..")) continue;
|
|
10221
10392
|
const r2 = rules.test(isDir2 ? `${rel}/` : rel);
|
|
10222
10393
|
if (r2.ignored) ignored = true;
|
|
@@ -10262,7 +10433,7 @@ function entryPoints(pkg) {
|
|
|
10262
10433
|
function npmWorkspaceRoot(absDir) {
|
|
10263
10434
|
for (let d = dirname6(absDir); ; d = dirname6(d)) {
|
|
10264
10435
|
try {
|
|
10265
|
-
const pj = JSON.parse(
|
|
10436
|
+
const pj = JSON.parse(readFileSync13(join15(d, "package.json"), "utf8"));
|
|
10266
10437
|
if (pj && pj.workspaces) return d;
|
|
10267
10438
|
} catch {
|
|
10268
10439
|
}
|
|
@@ -10281,7 +10452,7 @@ function workspaceRulesets(absDir) {
|
|
|
10281
10452
|
}
|
|
10282
10453
|
function listPackageFiles(dir, pkg) {
|
|
10283
10454
|
const absDir = resolve14(dir);
|
|
10284
|
-
const pj = pkg ?? JSON.parse(
|
|
10455
|
+
const pj = pkg ?? JSON.parse(readFileSync13(join15(absDir, "package.json"), "utf8"));
|
|
10285
10456
|
const files = filesPatterns(pj.files);
|
|
10286
10457
|
const never = (0, import_ignore.default)().add(NEVER_PACKED);
|
|
10287
10458
|
const forced = new Set(entryPoints(pj));
|
|
@@ -10290,12 +10461,12 @@ function listPackageFiles(dir, pkg) {
|
|
|
10290
10461
|
const isRoot = abs === absDir;
|
|
10291
10462
|
const own = isRoot && files ? null : readIgnoreFile(abs);
|
|
10292
10463
|
const here = own ? [...rulesets, own] : rulesets;
|
|
10293
|
-
const entries =
|
|
10464
|
+
const entries = readdirSync5(abs, { withFileTypes: true }).sort(
|
|
10294
10465
|
(a2, b) => a2.name < b.name ? -1 : a2.name > b.name ? 1 : 0
|
|
10295
10466
|
);
|
|
10296
10467
|
for (const entry of entries) {
|
|
10297
|
-
const childAbs =
|
|
10298
|
-
const rel = toPosix2(
|
|
10468
|
+
const childAbs = join15(abs, entry.name);
|
|
10469
|
+
const rel = toPosix2(relative3(absDir, childAbs));
|
|
10299
10470
|
if (entry.isSymbolicLink()) continue;
|
|
10300
10471
|
if (entry.isDirectory()) {
|
|
10301
10472
|
if (never.ignores(`${rel}/`)) continue;
|
|
@@ -10319,9 +10490,9 @@ function listPackageFiles(dir, pkg) {
|
|
|
10319
10490
|
function packSourceTarball(dir, pkg) {
|
|
10320
10491
|
const absDir = resolve14(dir);
|
|
10321
10492
|
const files = listPackageFiles(absDir, pkg).map((path2) => {
|
|
10322
|
-
const abs =
|
|
10323
|
-
const content =
|
|
10324
|
-
const mode =
|
|
10493
|
+
const abs = join15(absDir, path2);
|
|
10494
|
+
const content = readFileSync13(abs);
|
|
10495
|
+
const mode = statSync5(abs).mode & 73 ? 493 : 420;
|
|
10325
10496
|
return { path: path2, content, mode };
|
|
10326
10497
|
});
|
|
10327
10498
|
const tarball = packTar(
|
|
@@ -10347,11 +10518,11 @@ function tarballFilename(name, version) {
|
|
|
10347
10518
|
}
|
|
10348
10519
|
|
|
10349
10520
|
// src/registry/credentials.ts
|
|
10350
|
-
import { existsSync as
|
|
10521
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync4, readFileSync as readFileSync14, writeFileSync as writeFileSync5 } from "node:fs";
|
|
10351
10522
|
import { homedir } from "node:os";
|
|
10352
|
-
import { join as
|
|
10523
|
+
import { join as join16 } from "node:path";
|
|
10353
10524
|
function credentialsPath() {
|
|
10354
|
-
return
|
|
10525
|
+
return join16(homedir(), ".s2script", "credentials.json");
|
|
10355
10526
|
}
|
|
10356
10527
|
function normalizeRegistryUrl(url) {
|
|
10357
10528
|
const trimmed = url.replace(/\/$/, "");
|
|
@@ -10369,9 +10540,9 @@ function loadCredentials() {
|
|
|
10369
10540
|
return { registryUrl: defaultRegistryUrl(), token: fromEnv };
|
|
10370
10541
|
}
|
|
10371
10542
|
const p = credentialsPath();
|
|
10372
|
-
if (!
|
|
10543
|
+
if (!existsSync11(p)) return null;
|
|
10373
10544
|
try {
|
|
10374
|
-
const j = JSON.parse(
|
|
10545
|
+
const j = JSON.parse(readFileSync14(p, "utf8"));
|
|
10375
10546
|
if (!j.token) return null;
|
|
10376
10547
|
return {
|
|
10377
10548
|
registryUrl: normalizeRegistryUrl(j.registryUrl || defaultRegistryUrl()),
|
|
@@ -10382,7 +10553,7 @@ function loadCredentials() {
|
|
|
10382
10553
|
}
|
|
10383
10554
|
}
|
|
10384
10555
|
function saveCredentials(creds) {
|
|
10385
|
-
const dir =
|
|
10556
|
+
const dir = join16(homedir(), ".s2script");
|
|
10386
10557
|
mkdirSync4(dir, { recursive: true });
|
|
10387
10558
|
writeFileSync5(
|
|
10388
10559
|
credentialsPath(),
|
|
@@ -10630,10 +10801,10 @@ function assertDeployable(pkg, label) {
|
|
|
10630
10801
|
}
|
|
10631
10802
|
var MAX_README_CHARS = 1e5;
|
|
10632
10803
|
function readPackageReadme(pluginDir) {
|
|
10633
|
-
const names =
|
|
10804
|
+
const names = readdirSync6(pluginDir).filter((n3) => /^readme(\.(md|markdown))?$/i.test(n3));
|
|
10634
10805
|
if (names.length === 0) return null;
|
|
10635
10806
|
const name = names.find((n3) => n3 === "README.md") ?? names.sort()[0];
|
|
10636
|
-
const text3 =
|
|
10807
|
+
const text3 = readFileSync15(resolve15(pluginDir, name), "utf8").trim();
|
|
10637
10808
|
if (!text3) return null;
|
|
10638
10809
|
if (text3.length > MAX_README_CHARS) {
|
|
10639
10810
|
throw new Error(
|
|
@@ -10657,7 +10828,7 @@ function assembleDeployArchive(pluginDir, pkg, outPath, opts = {}) {
|
|
|
10657
10828
|
const absDir = resolve15(pluginDir);
|
|
10658
10829
|
const access = opts.access ?? resolveAccess(pkg);
|
|
10659
10830
|
if (packageKind(pkg) === "library") {
|
|
10660
|
-
const lib =
|
|
10831
|
+
const lib = readFileSync15(outPath);
|
|
10661
10832
|
const manifestEntry2 = unzipSync(lib)["manifest.json"];
|
|
10662
10833
|
if (!manifestEntry2) {
|
|
10663
10834
|
throw new Error(`built archive missing manifest.json: ${outPath}`);
|
|
@@ -10674,7 +10845,7 @@ function assembleDeployArchive(pluginDir, pkg, outPath, opts = {}) {
|
|
|
10674
10845
|
}
|
|
10675
10846
|
const gate = assertPublishesTypes(pkg, absDir);
|
|
10676
10847
|
if (!gate.ok) throw new Error(`publish gate failed: ${gate.error}`);
|
|
10677
|
-
const s2sp =
|
|
10848
|
+
const s2sp = readFileSync15(outPath);
|
|
10678
10849
|
const manifestEntry = unzipSync(s2sp)["manifest.json"];
|
|
10679
10850
|
if (!manifestEntry) {
|
|
10680
10851
|
throw new Error(`built archive missing manifest.json: ${outPath}`);
|
|
@@ -10700,7 +10871,7 @@ function assembleDeployArchive(pluginDir, pkg, outPath, opts = {}) {
|
|
|
10700
10871
|
}
|
|
10701
10872
|
async function deployPlugin(opts) {
|
|
10702
10873
|
const absDir = resolve15(opts.dir);
|
|
10703
|
-
const pkg = JSON.parse(
|
|
10874
|
+
const pkg = JSON.parse(readFileSync15(resolve15(absDir, "package.json"), "utf8"));
|
|
10704
10875
|
assertDeployable(pkg, absDir);
|
|
10705
10876
|
const access = resolveAccess(pkg, opts.access);
|
|
10706
10877
|
assertAccessAllowed(pkg.name ?? absDir, access);
|
|
@@ -11041,14 +11212,14 @@ async function runWorkspaceDeploy(opts) {
|
|
|
11041
11212
|
import { resolve as resolve17 } from "node:path";
|
|
11042
11213
|
|
|
11043
11214
|
// src/version/version.ts
|
|
11044
|
-
import { existsSync as
|
|
11045
|
-
import { join as
|
|
11215
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
11216
|
+
import { join as join20 } from "node:path";
|
|
11046
11217
|
|
|
11047
11218
|
// src/version/changesets.ts
|
|
11048
11219
|
var import_semver = __toESM(require_semver2(), 1);
|
|
11049
|
-
import { readFileSync as
|
|
11220
|
+
import { readFileSync as readFileSync16 } from "node:fs";
|
|
11050
11221
|
import { createRequire as createRequire2 } from "node:module";
|
|
11051
|
-
import { join as
|
|
11222
|
+
import { join as join17 } from "node:path";
|
|
11052
11223
|
import { pathToFileURL } from "node:url";
|
|
11053
11224
|
var SUPPORTED = {
|
|
11054
11225
|
"@changesets/assemble-release-plan": ">=6.0.0 <7.0.0",
|
|
@@ -11068,7 +11239,7 @@ function named(mod, key) {
|
|
|
11068
11239
|
return outer?.[key];
|
|
11069
11240
|
}
|
|
11070
11241
|
async function loadChangesets(workspaceRoot) {
|
|
11071
|
-
const require3 = createRequire2(
|
|
11242
|
+
const require3 = createRequire2(join17(workspaceRoot, "package.json"));
|
|
11072
11243
|
const missing = [];
|
|
11073
11244
|
const wrongVersion = [];
|
|
11074
11245
|
const resolved = /* @__PURE__ */ new Map();
|
|
@@ -11083,7 +11254,7 @@ async function loadChangesets(workspaceRoot) {
|
|
|
11083
11254
|
missing.push(name);
|
|
11084
11255
|
continue;
|
|
11085
11256
|
}
|
|
11086
|
-
const version = String(JSON.parse(
|
|
11257
|
+
const version = String(JSON.parse(readFileSync16(manifest, "utf8")).version ?? "");
|
|
11087
11258
|
if (!(0, import_semver.satisfies)(version, range2, { includePrerelease: true })) {
|
|
11088
11259
|
wrongVersion.push(`${name}@${version} (supported: ${range2})`);
|
|
11089
11260
|
continue;
|
|
@@ -11183,8 +11354,8 @@ function mirrorPackages(ws) {
|
|
|
11183
11354
|
|
|
11184
11355
|
// src/version/ranges.ts
|
|
11185
11356
|
var import_semver2 = __toESM(require_semver2(), 1);
|
|
11186
|
-
import { readFileSync as
|
|
11187
|
-
import { join as
|
|
11357
|
+
import { readFileSync as readFileSync17, writeFileSync as writeFileSync6 } from "node:fs";
|
|
11358
|
+
import { join as join18 } from "node:path";
|
|
11188
11359
|
var BUMP_LEVEL = { none: 0, patch: 1, minor: 2, major: 3 };
|
|
11189
11360
|
function rangePrefix(range2) {
|
|
11190
11361
|
if (range2.startsWith(">=")) return ">=";
|
|
@@ -11203,7 +11374,7 @@ function shouldUpdate(release, range2, config) {
|
|
|
11203
11374
|
return BUMP_LEVEL[release.type] >= minLevel;
|
|
11204
11375
|
}
|
|
11205
11376
|
function readJsonFile(path2) {
|
|
11206
|
-
const raw =
|
|
11377
|
+
const raw = readFileSync17(path2, "utf8");
|
|
11207
11378
|
const match2 = /^[ \t]*[{[]\s*\n([ \t]+)/.exec(raw);
|
|
11208
11379
|
return {
|
|
11209
11380
|
json: JSON.parse(raw),
|
|
@@ -11244,7 +11415,7 @@ function rewriteSiblingRanges(ws, releases, config) {
|
|
|
11244
11415
|
for (const [consumerName, ifaceRanges] of edits) {
|
|
11245
11416
|
const plugin = ws.plugins.find((p) => p.name === consumerName);
|
|
11246
11417
|
if (plugin === void 0) continue;
|
|
11247
|
-
const path2 =
|
|
11418
|
+
const path2 = join18(plugin.dir, "package.json");
|
|
11248
11419
|
const { json, indent, eol } = readJsonFile(path2);
|
|
11249
11420
|
const s2 = json.s2script;
|
|
11250
11421
|
if (s2?.pluginDependencies === void 0) continue;
|
|
@@ -11258,7 +11429,7 @@ function rewriteSiblingRanges(ws, releases, config) {
|
|
|
11258
11429
|
// src/version/bundle-bump.ts
|
|
11259
11430
|
var import_semver3 = __toESM(require_semver2(), 1);
|
|
11260
11431
|
import { writeFileSync as writeFileSync7 } from "node:fs";
|
|
11261
|
-
import { join as
|
|
11432
|
+
import { join as join19 } from "node:path";
|
|
11262
11433
|
var LEVEL = { none: 0, patch: 1, minor: 2, major: 3 };
|
|
11263
11434
|
function plannedBundleBump(ws, releases) {
|
|
11264
11435
|
const bundle = readBundle(ws);
|
|
@@ -11282,7 +11453,7 @@ function plannedBundleBump(ws, releases) {
|
|
|
11282
11453
|
function bumpBundle(ws, releases) {
|
|
11283
11454
|
const bump = plannedBundleBump(ws, releases);
|
|
11284
11455
|
if (!bump) return { bump: null, touchedFiles: [] };
|
|
11285
|
-
const path2 =
|
|
11456
|
+
const path2 = join19(ws.root, "package.json");
|
|
11286
11457
|
const { json, indent, eol } = readJsonFile(path2);
|
|
11287
11458
|
json.version = bump.to;
|
|
11288
11459
|
writeFileSync7(path2, JSON.stringify(json, null, indent) + eol);
|
|
@@ -11292,8 +11463,8 @@ function bumpBundle(ws, releases) {
|
|
|
11292
11463
|
// src/version/version.ts
|
|
11293
11464
|
async function versionWorkspace(root, opts = {}) {
|
|
11294
11465
|
const ws = loadWorkspace(root);
|
|
11295
|
-
const configPath =
|
|
11296
|
-
if (!
|
|
11466
|
+
const configPath = join20(ws.root, ".changeset", "config.json");
|
|
11467
|
+
if (!existsSync12(configPath)) {
|
|
11297
11468
|
throw new Error(
|
|
11298
11469
|
`s2s version: ${configPath} does not exist \u2014 this workspace is not set up for changesets. Run \`npx changeset init\` at ${ws.root}.`
|
|
11299
11470
|
);
|
|
@@ -11380,15 +11551,15 @@ import { resolve as resolve19 } from "node:path";
|
|
|
11380
11551
|
import {
|
|
11381
11552
|
mkdirSync as mkdirSync6,
|
|
11382
11553
|
writeFileSync as writeFileSync10,
|
|
11383
|
-
readFileSync as
|
|
11384
|
-
existsSync as
|
|
11554
|
+
readFileSync as readFileSync19,
|
|
11555
|
+
existsSync as existsSync14
|
|
11385
11556
|
} from "node:fs";
|
|
11386
|
-
import { join as
|
|
11557
|
+
import { join as join23, resolve as resolve18 } from "node:path";
|
|
11387
11558
|
import { gunzipSync } from "node:zlib";
|
|
11388
11559
|
|
|
11389
11560
|
// src/registry/npmrc.ts
|
|
11390
|
-
import { existsSync as
|
|
11391
|
-
import { join as
|
|
11561
|
+
import { existsSync as existsSync13, readFileSync as readFileSync18, writeFileSync as writeFileSync8 } from "node:fs";
|
|
11562
|
+
import { join as join21 } from "node:path";
|
|
11392
11563
|
function npmCompatRegistryUrl(registryUrl) {
|
|
11393
11564
|
return `${registryUrl.replace(/\/$/, "")}/npm/`;
|
|
11394
11565
|
}
|
|
@@ -11404,8 +11575,8 @@ function ensureScopeNpmrc(projectDir, packageName, registryUrl) {
|
|
|
11404
11575
|
const compat = npmCompatRegistryUrl(registryUrl);
|
|
11405
11576
|
const key = `@${scope}:registry`;
|
|
11406
11577
|
const line = `${key}=${compat}`;
|
|
11407
|
-
const npmrcPath =
|
|
11408
|
-
let existing =
|
|
11578
|
+
const npmrcPath = join21(projectDir, ".npmrc");
|
|
11579
|
+
let existing = existsSync13(npmrcPath) ? readFileSync18(npmrcPath, "utf8") : "";
|
|
11409
11580
|
const lines = existing.split(/\r?\n/);
|
|
11410
11581
|
const idx = lines.findIndex((l2) => l2.trimStart().startsWith(`${key}=`) || l2.trimStart().startsWith(`${key} =`));
|
|
11411
11582
|
if (idx >= 0) {
|
|
@@ -11421,7 +11592,7 @@ function ensureScopeNpmrc(projectDir, packageName, registryUrl) {
|
|
|
11421
11592
|
|
|
11422
11593
|
// src/registry/lib-extract.ts
|
|
11423
11594
|
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync9 } from "node:fs";
|
|
11424
|
-
import { join as
|
|
11595
|
+
import { join as join22 } from "node:path";
|
|
11425
11596
|
var WANTED = /* @__PURE__ */ new Set(["index.js", "index.d.ts"]);
|
|
11426
11597
|
function extractLibArchive(s2lib, outDir, meta) {
|
|
11427
11598
|
const entries = unzipSync(new Uint8Array(s2lib));
|
|
@@ -11430,7 +11601,7 @@ function extractLibArchive(s2lib, outDir, meta) {
|
|
|
11430
11601
|
mkdirSync5(outDir, { recursive: true });
|
|
11431
11602
|
for (const [name, bytes] of Object.entries(entries)) {
|
|
11432
11603
|
if (!WANTED.has(name)) continue;
|
|
11433
|
-
writeFileSync9(
|
|
11604
|
+
writeFileSync9(join22(outDir, name), Buffer.from(bytes));
|
|
11434
11605
|
}
|
|
11435
11606
|
let apiVersion = "1.x";
|
|
11436
11607
|
try {
|
|
@@ -11439,7 +11610,7 @@ function extractLibArchive(s2lib, outDir, meta) {
|
|
|
11439
11610
|
} catch {
|
|
11440
11611
|
}
|
|
11441
11612
|
writeFileSync9(
|
|
11442
|
-
|
|
11613
|
+
join22(outDir, "package.json"),
|
|
11443
11614
|
JSON.stringify(
|
|
11444
11615
|
{ name: meta.name, version: meta.version, main: "index.js", types: "index.d.ts", s2script: { kind: "library", apiVersion } },
|
|
11445
11616
|
null,
|
|
@@ -11476,13 +11647,13 @@ function extractTypesTarball(tgz, outDir) {
|
|
|
11476
11647
|
if (!name || name.endsWith("/")) continue;
|
|
11477
11648
|
const base = name.replace(/^package\//, "");
|
|
11478
11649
|
if (base === "package.json") {
|
|
11479
|
-
writeFileSync10(
|
|
11650
|
+
writeFileSync10(join23(outDir, "package.json"), content);
|
|
11480
11651
|
} else if (base === "api.d.ts" || base === "index.d.ts") {
|
|
11481
|
-
writeFileSync10(
|
|
11652
|
+
writeFileSync10(join23(outDir, "index.d.ts"), content);
|
|
11482
11653
|
wroteContract = true;
|
|
11483
11654
|
}
|
|
11484
11655
|
}
|
|
11485
|
-
if (!wroteContract && !
|
|
11656
|
+
if (!wroteContract && !existsSync14(join23(outDir, "index.d.ts"))) {
|
|
11486
11657
|
throw new Error("types tarball missing package/api.d.ts (or index.d.ts)");
|
|
11487
11658
|
}
|
|
11488
11659
|
}
|
|
@@ -11507,10 +11678,10 @@ async function addPackage(opts) {
|
|
|
11507
11678
|
}
|
|
11508
11679
|
if (resolved.kind === "library") {
|
|
11509
11680
|
const s2lib = await client.downloadLib(name, resolved.version);
|
|
11510
|
-
const libDir =
|
|
11681
|
+
const libDir = join23(absDir, ".s2script", "libs", ...name.split("/"));
|
|
11511
11682
|
extractLibArchive(s2lib, libDir, { name, version: resolved.version });
|
|
11512
|
-
const pkgPath2 =
|
|
11513
|
-
const pkg2 = JSON.parse(
|
|
11683
|
+
const pkgPath2 = join23(absDir, "package.json");
|
|
11684
|
+
const pkg2 = JSON.parse(readFileSync19(pkgPath2, "utf8"));
|
|
11514
11685
|
pkg2.s2script = pkg2.s2script ?? {};
|
|
11515
11686
|
pkg2.s2script.libraries = pkg2.s2script.libraries ?? {};
|
|
11516
11687
|
pkg2.s2script.libraries[name] = rangeForResolved(range2, resolved.version);
|
|
@@ -11531,10 +11702,10 @@ async function addPackage(opts) {
|
|
|
11531
11702
|
throw new Error(`${name}@${resolved.version} has no types artifact (runtime-only package?)`);
|
|
11532
11703
|
}
|
|
11533
11704
|
const tgz = await client.downloadTypes(name, resolved.version);
|
|
11534
|
-
const typesDir =
|
|
11705
|
+
const typesDir = join23(absDir, ".s2script", "types", ...name.split("/"));
|
|
11535
11706
|
extractTypesTarball(tgz, typesDir);
|
|
11536
|
-
const pkgPath =
|
|
11537
|
-
const pkg = JSON.parse(
|
|
11707
|
+
const pkgPath = join23(absDir, "package.json");
|
|
11708
|
+
const pkg = JSON.parse(readFileSync19(pkgPath, "utf8"));
|
|
11538
11709
|
pkg.s2script = pkg.s2script ?? {};
|
|
11539
11710
|
pkg.s2script.pluginDependencies = pkg.s2script.pluginDependencies ?? {};
|
|
11540
11711
|
pkg.s2script.pluginDependencies[name] = rangeForResolved(range2, resolved.version);
|
|
@@ -11615,37 +11786,37 @@ async function run4(argv2) {
|
|
|
11615
11786
|
}
|
|
11616
11787
|
|
|
11617
11788
|
// src/commands/install.ts
|
|
11618
|
-
import { existsSync as
|
|
11619
|
-
import { join as
|
|
11789
|
+
import { existsSync as existsSync19, writeFileSync as writeFileSync15 } from "node:fs";
|
|
11790
|
+
import { join as join27 } from "node:path";
|
|
11620
11791
|
|
|
11621
11792
|
// src/server/manifest.ts
|
|
11622
11793
|
var import_semver4 = __toESM(require_semver2(), 1);
|
|
11623
|
-
import { existsSync as
|
|
11624
|
-
import { basename as basename2, join as
|
|
11794
|
+
import { existsSync as existsSync15, readFileSync as readFileSync20, renameSync, writeFileSync as writeFileSync11 } from "node:fs";
|
|
11795
|
+
import { basename as basename2, join as join24, resolve as resolve20 } from "node:path";
|
|
11625
11796
|
var SERVER_MANIFEST = "plugins.json";
|
|
11626
11797
|
var SERVER_LOCK = "plugins-lock.json";
|
|
11627
11798
|
var PLUGINS_SUBDIR = "plugins";
|
|
11628
11799
|
var DISABLED_SUBDIR = "disabled";
|
|
11629
11800
|
function readJson(path2) {
|
|
11630
|
-
const j = JSON.parse(
|
|
11801
|
+
const j = JSON.parse(readFileSync20(path2, "utf8"));
|
|
11631
11802
|
if (!j || typeof j !== "object" || Array.isArray(j)) throw new Error(`${path2}: must be a JSON object`);
|
|
11632
11803
|
return j;
|
|
11633
11804
|
}
|
|
11634
11805
|
function findServerRoot(start) {
|
|
11635
11806
|
for (const dir of [resolve20(start), resolve20(start, "addons", "s2script")]) {
|
|
11636
|
-
if (
|
|
11807
|
+
if (existsSync15(join24(dir, SERVER_MANIFEST))) return dir;
|
|
11637
11808
|
}
|
|
11638
11809
|
return null;
|
|
11639
11810
|
}
|
|
11640
11811
|
function findAddonRoot(start) {
|
|
11641
11812
|
const found = findServerRoot(start);
|
|
11642
11813
|
if (found) return found;
|
|
11643
|
-
if (
|
|
11814
|
+
if (existsSync15(resolve20(start, PLUGINS_SUBDIR))) return resolve20(start);
|
|
11644
11815
|
const nested = resolve20(start, "addons", "s2script");
|
|
11645
|
-
return
|
|
11816
|
+
return existsSync15(nested) ? nested : null;
|
|
11646
11817
|
}
|
|
11647
11818
|
function parseServerManifest(root, raw) {
|
|
11648
|
-
const label =
|
|
11819
|
+
const label = join24(root, SERVER_MANIFEST);
|
|
11649
11820
|
const depsRaw = raw.dependencies ?? {};
|
|
11650
11821
|
if (typeof depsRaw !== "object" || Array.isArray(depsRaw)) {
|
|
11651
11822
|
throw new Error(`${label}: "dependencies" must be an object (plugin name \u2192 version range)`);
|
|
@@ -11694,8 +11865,8 @@ function parseServerManifest(root, raw) {
|
|
|
11694
11865
|
};
|
|
11695
11866
|
}
|
|
11696
11867
|
function readServerManifest(root) {
|
|
11697
|
-
const path2 =
|
|
11698
|
-
if (!
|
|
11868
|
+
const path2 = join24(root, SERVER_MANIFEST);
|
|
11869
|
+
if (!existsSync15(path2)) throw new Error(`no ${SERVER_MANIFEST} in ${root} \u2014 run \`s2s server init\` first`);
|
|
11699
11870
|
return parseServerManifest(root, readJson(path2));
|
|
11700
11871
|
}
|
|
11701
11872
|
function newServerManifestJson(name, dependencies) {
|
|
@@ -11709,15 +11880,15 @@ function writeServerManifest(m) {
|
|
|
11709
11880
|
else delete out.with;
|
|
11710
11881
|
if (m.disabled.length > 0) out.disabled = [...m.disabled].sort();
|
|
11711
11882
|
else delete out.disabled;
|
|
11712
|
-
const path2 =
|
|
11883
|
+
const path2 = join24(m.root, SERVER_MANIFEST);
|
|
11713
11884
|
const tmp = `${path2}.${process.pid}.tmp`;
|
|
11714
11885
|
writeFileSync11(tmp, JSON.stringify(out, null, 2) + "\n");
|
|
11715
11886
|
renameSync(tmp, path2);
|
|
11716
11887
|
}
|
|
11717
11888
|
|
|
11718
11889
|
// src/server/commands.ts
|
|
11719
|
-
import { existsSync as
|
|
11720
|
-
import { join as
|
|
11890
|
+
import { existsSync as existsSync18, readdirSync as readdirSync7, readFileSync as readFileSync23, writeFileSync as writeFileSync14 } from "node:fs";
|
|
11891
|
+
import { join as join26, resolve as resolve22 } from "node:path";
|
|
11721
11892
|
var import_semver5 = __toESM(require_semver2(), 1);
|
|
11722
11893
|
|
|
11723
11894
|
// src/registry/install.ts
|
|
@@ -11770,7 +11941,7 @@ async function resolveMerged(client, specs, withMembers = {}) {
|
|
|
11770
11941
|
|
|
11771
11942
|
// src/server/lock.ts
|
|
11772
11943
|
import { createHash as createHash4 } from "node:crypto";
|
|
11773
|
-
import { existsSync as
|
|
11944
|
+
import { existsSync as existsSync16, readFileSync as readFileSync21, renameSync as renameSync2, writeFileSync as writeFileSync12 } from "node:fs";
|
|
11774
11945
|
var LOCKFILE_VERSION = 3;
|
|
11775
11946
|
function integrityFromSha256Hex(hex) {
|
|
11776
11947
|
return `sha256-${Buffer.from(hex, "hex").toString("base64")}`;
|
|
@@ -11844,8 +12015,8 @@ function parseLock(text3, label = "plugins-lock.json") {
|
|
|
11844
12015
|
};
|
|
11845
12016
|
}
|
|
11846
12017
|
function readLock(path2) {
|
|
11847
|
-
if (!
|
|
11848
|
-
return parseLock(
|
|
12018
|
+
if (!existsSync16(path2)) return null;
|
|
12019
|
+
return parseLock(readFileSync21(path2, "utf8"), path2);
|
|
11849
12020
|
}
|
|
11850
12021
|
function writeLock(path2, lock) {
|
|
11851
12022
|
const tmp = `${path2}.${process.pid}.tmp`;
|
|
@@ -11854,8 +12025,8 @@ function writeLock(path2, lock) {
|
|
|
11854
12025
|
}
|
|
11855
12026
|
|
|
11856
12027
|
// src/server/sync.ts
|
|
11857
|
-
import { existsSync as
|
|
11858
|
-
import { dirname as dirname7, join as
|
|
12028
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync7, readFileSync as readFileSync22, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync13 } from "node:fs";
|
|
12029
|
+
import { dirname as dirname7, join as join25, resolve as resolve21, sep as sep5 } from "node:path";
|
|
11859
12030
|
function relPath(t2) {
|
|
11860
12031
|
return t2.disabled ? `${DISABLED_SUBDIR}/${t2.filename}` : t2.filename;
|
|
11861
12032
|
}
|
|
@@ -11936,18 +12107,18 @@ async function syncPlugins(opts) {
|
|
|
11936
12107
|
try {
|
|
11937
12108
|
for (const t2 of opts.targets) {
|
|
11938
12109
|
const key = lockKey(relPath(t2));
|
|
11939
|
-
const dest =
|
|
12110
|
+
const dest = join25(dir, relPath(t2));
|
|
11940
12111
|
result.plugins[key] = {
|
|
11941
12112
|
name: t2.name,
|
|
11942
12113
|
version: t2.version,
|
|
11943
12114
|
resolved: t2.url,
|
|
11944
12115
|
integrity: integrityFromSha256Hex(t2.sha256)
|
|
11945
12116
|
};
|
|
11946
|
-
if (
|
|
12117
|
+
if (existsSync17(dest) && sha256Hex(readFileSync22(dest)) === t2.sha256) {
|
|
11947
12118
|
result.kept.push(t2.filename);
|
|
11948
12119
|
continue;
|
|
11949
12120
|
}
|
|
11950
|
-
const movedFrom = Object.entries(opts.oldLock?.plugins ?? {}).filter(([k, p]) => k !== key && p.name === t2.name).map(([k]) =>
|
|
12121
|
+
const movedFrom = Object.entries(opts.oldLock?.plugins ?? {}).filter(([k, p]) => k !== key && p.name === t2.name).map(([k]) => join25(opts.root, k)).find((f) => existsSync17(f) && sha256Hex(readFileSync22(f)) === t2.sha256);
|
|
11951
12122
|
if (movedFrom) {
|
|
11952
12123
|
result.moved.push(t2.filename);
|
|
11953
12124
|
if (opts.dryRun) log3(`would ${t2.disabled ? "disable" : "enable"} ${t2.name}@${t2.version}`);
|
|
@@ -11984,10 +12155,10 @@ async function syncPlugins(opts) {
|
|
|
11984
12155
|
}
|
|
11985
12156
|
for (const [key, old] of Object.entries(opts.oldLock?.plugins ?? {})) {
|
|
11986
12157
|
if (key in result.plugins) continue;
|
|
11987
|
-
const file =
|
|
11988
|
-
if (!
|
|
12158
|
+
const file = join25(opts.root, key);
|
|
12159
|
+
if (!existsSync17(file)) continue;
|
|
11989
12160
|
const want = sha256HexFromIntegrity(old.integrity);
|
|
11990
|
-
if (want && sha256Hex(
|
|
12161
|
+
if (want && sha256Hex(readFileSync22(file)) === want) {
|
|
11991
12162
|
if (opts.dryRun) log3(`would remove ${old.name}@${old.version} (${key})`);
|
|
11992
12163
|
else {
|
|
11993
12164
|
rmSync3(file);
|
|
@@ -12039,7 +12210,7 @@ async function serverInstall(opts) {
|
|
|
12039
12210
|
}
|
|
12040
12211
|
manifest = { ...manifest, with: { ...manifest.with, [parseSpec2(opts.specs[0]).name]: opts.with } };
|
|
12041
12212
|
}
|
|
12042
|
-
const lockPath =
|
|
12213
|
+
const lockPath = join26(opts.root, SERVER_LOCK);
|
|
12043
12214
|
const lock = readLock(lockPath);
|
|
12044
12215
|
if (opts.disabled) {
|
|
12045
12216
|
if (!opts.specs?.length) throw new Error("--disabled needs the plugins to install: s2s install <name> --disabled");
|
|
@@ -12090,7 +12261,7 @@ async function serverUpdate(opts) {
|
|
|
12090
12261
|
const log3 = opts.log ?? (() => {
|
|
12091
12262
|
});
|
|
12092
12263
|
const manifest = readServerManifest(opts.root);
|
|
12093
|
-
const lockPath =
|
|
12264
|
+
const lockPath = join26(opts.root, SERVER_LOCK);
|
|
12094
12265
|
const lock = readLock(lockPath);
|
|
12095
12266
|
const names = opts.names && opts.names.length > 0 ? opts.names : Object.keys(manifest.dependencies);
|
|
12096
12267
|
for (const n3 of names) {
|
|
@@ -12108,12 +12279,12 @@ async function serverUpdate(opts) {
|
|
|
12108
12279
|
}
|
|
12109
12280
|
function scanLocalPlugins(root, onUnreadable = () => {
|
|
12110
12281
|
}) {
|
|
12111
|
-
const dir =
|
|
12112
|
-
if (!
|
|
12282
|
+
const dir = join26(root, PLUGINS_SUBDIR);
|
|
12283
|
+
if (!existsSync18(dir)) return [];
|
|
12113
12284
|
const out = [];
|
|
12114
|
-
for (const entry of
|
|
12285
|
+
for (const entry of readdirSync7(dir, { withFileTypes: true })) {
|
|
12115
12286
|
if (!entry.isFile() || !entry.name.endsWith(".s2sp")) continue;
|
|
12116
|
-
const bytes =
|
|
12287
|
+
const bytes = readFileSync23(join26(dir, entry.name));
|
|
12117
12288
|
try {
|
|
12118
12289
|
const files = unzipSync(new Uint8Array(bytes), { filter: (f) => f.name === "manifest.json" });
|
|
12119
12290
|
const m = JSON.parse(Buffer.from(files["manifest.json"]).toString("utf8"));
|
|
@@ -12127,8 +12298,8 @@ function scanLocalPlugins(root, onUnreadable = () => {
|
|
|
12127
12298
|
}
|
|
12128
12299
|
async function serverInit(opts) {
|
|
12129
12300
|
const root = resolve22(opts.root);
|
|
12130
|
-
const pkgPath =
|
|
12131
|
-
if (
|
|
12301
|
+
const pkgPath = join26(root, SERVER_MANIFEST);
|
|
12302
|
+
if (existsSync18(pkgPath) && !opts.force) {
|
|
12132
12303
|
throw new Error(`${pkgPath} already exists \u2014 pass --force to replace it`);
|
|
12133
12304
|
}
|
|
12134
12305
|
const report = { managed: [], unmanaged: [] };
|
|
@@ -12169,7 +12340,7 @@ async function serverInit(opts) {
|
|
|
12169
12340
|
const raw = newServerManifestJson(opts.name ?? "s2script-server", dependencies);
|
|
12170
12341
|
writeFileSync14(pkgPath, JSON.stringify(raw, null, 2) + "\n");
|
|
12171
12342
|
const manifest = parseServerManifest(root, raw);
|
|
12172
|
-
writeLock(
|
|
12343
|
+
writeLock(join26(root, SERVER_LOCK), lockFor(manifest, plugins));
|
|
12173
12344
|
return report;
|
|
12174
12345
|
}
|
|
12175
12346
|
async function serverSetEnabled(opts) {
|
|
@@ -12187,7 +12358,7 @@ async function serverSetEnabled(opts) {
|
|
|
12187
12358
|
else set.add(n3);
|
|
12188
12359
|
}
|
|
12189
12360
|
manifest = { ...manifest, disabled: [...set].sort() };
|
|
12190
|
-
const lockPath =
|
|
12361
|
+
const lockPath = join26(opts.root, SERVER_LOCK);
|
|
12191
12362
|
const lock = readLock(lockPath);
|
|
12192
12363
|
const specs = pinnedSpecs(manifest, lock, sat);
|
|
12193
12364
|
const { targets } = await resolveTargets(opts.client, specs, manifest.with, {
|
|
@@ -12259,11 +12430,11 @@ async function run5(argv2) {
|
|
|
12259
12430
|
}
|
|
12260
12431
|
await runServer(async () => {
|
|
12261
12432
|
const withMembers = collectWith(argv2);
|
|
12262
|
-
if (!
|
|
12433
|
+
if (!existsSync19(join27(root, SERVER_MANIFEST))) {
|
|
12263
12434
|
if (dryRun) throw new Error(`no ${SERVER_MANIFEST} in ${root} yet \u2014 run without --dry-run to create one`);
|
|
12264
12435
|
const fresh = newServerManifestJson("s2script-server", {});
|
|
12265
|
-
writeFileSync15(
|
|
12266
|
-
console.log(`created ${
|
|
12436
|
+
writeFileSync15(join27(root, SERVER_MANIFEST), JSON.stringify(fresh, null, 2) + "\n");
|
|
12437
|
+
console.log(`created ${join27(root, SERVER_MANIFEST)}`);
|
|
12267
12438
|
}
|
|
12268
12439
|
return serverInstall({
|
|
12269
12440
|
root,
|
|
@@ -12284,26 +12455,26 @@ import { resolve as resolve25 } from "node:path";
|
|
|
12284
12455
|
import {
|
|
12285
12456
|
mkdirSync as mkdirSync8,
|
|
12286
12457
|
writeFileSync as writeFileSync16,
|
|
12287
|
-
existsSync as
|
|
12288
|
-
readdirSync as
|
|
12289
|
-
readFileSync as
|
|
12458
|
+
existsSync as existsSync20,
|
|
12459
|
+
readdirSync as readdirSync8,
|
|
12460
|
+
readFileSync as readFileSync24,
|
|
12290
12461
|
symlinkSync
|
|
12291
12462
|
} from "node:fs";
|
|
12292
|
-
import { dirname as dirname8, isAbsolute, join as
|
|
12463
|
+
import { dirname as dirname8, isAbsolute, join as join28, relative as relative4, resolve as resolve23, basename as basename4 } from "node:path";
|
|
12293
12464
|
import { spawnSync } from "node:child_process";
|
|
12294
12465
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
12295
12466
|
function readCliVersion() {
|
|
12296
12467
|
const here = dirname8(fileURLToPath2(import.meta.url));
|
|
12297
12468
|
const candidates = [
|
|
12298
|
-
|
|
12469
|
+
join28(here, "..", "package.json"),
|
|
12299
12470
|
// dist/cli.js → packages/sdk/package.json
|
|
12300
|
-
|
|
12471
|
+
join28(here, "..", "..", "package.json")
|
|
12301
12472
|
// src/create → packages/sdk/package.json
|
|
12302
12473
|
];
|
|
12303
12474
|
for (const p of candidates) {
|
|
12304
|
-
if (!
|
|
12475
|
+
if (!existsSync20(p)) continue;
|
|
12305
12476
|
try {
|
|
12306
|
-
const pkg = JSON.parse(
|
|
12477
|
+
const pkg = JSON.parse(readFileSync24(p, "utf8"));
|
|
12307
12478
|
if (pkg.name === "@s2script/sdk" && pkg.version) return pkg.version;
|
|
12308
12479
|
} catch {
|
|
12309
12480
|
}
|
|
@@ -12313,9 +12484,9 @@ function readCliVersion() {
|
|
|
12313
12484
|
function findLocalPackagesDir() {
|
|
12314
12485
|
const here = dirname8(fileURLToPath2(import.meta.url));
|
|
12315
12486
|
const candidates = [
|
|
12316
|
-
|
|
12487
|
+
join28(here, "..", ".."),
|
|
12317
12488
|
// dist/cli.js → packages
|
|
12318
|
-
|
|
12489
|
+
join28(here, "..", "..", "..")
|
|
12319
12490
|
// src/create → packages
|
|
12320
12491
|
];
|
|
12321
12492
|
for (const c2 of candidates) {
|
|
@@ -12331,8 +12502,8 @@ function defaultNameFromPath(dir, kind = "plugin") {
|
|
|
12331
12502
|
return `@${kind}/${slugifyBasename(dir)}`;
|
|
12332
12503
|
}
|
|
12333
12504
|
function assertEmptyTarget(targetPath) {
|
|
12334
|
-
if (!
|
|
12335
|
-
const kids =
|
|
12505
|
+
if (!existsSync20(targetPath)) return;
|
|
12506
|
+
const kids = readdirSync8(targetPath);
|
|
12336
12507
|
const meaningful = kids.filter((k) => k !== ".git");
|
|
12337
12508
|
if (meaningful.length) {
|
|
12338
12509
|
throw new Error(`target directory is not empty: ${targetPath}`);
|
|
@@ -12380,8 +12551,8 @@ function registryDevDeps(game, sdkVersion, resolve29 = resolvePublishedVersion)
|
|
|
12380
12551
|
function fileDevDeps(packagesDir, game) {
|
|
12381
12552
|
const deps = {};
|
|
12382
12553
|
for (const n3 of createPackageNames(game)) {
|
|
12383
|
-
const abs =
|
|
12384
|
-
if (!
|
|
12554
|
+
const abs = join28(packagesDir, n3);
|
|
12555
|
+
if (!existsSync20(join28(abs, "package.json"))) return void 0;
|
|
12385
12556
|
deps[`@s2script/${n3}`] = `file:${abs}`;
|
|
12386
12557
|
}
|
|
12387
12558
|
return deps;
|
|
@@ -12446,7 +12617,7 @@ function tsconfigJson() {
|
|
|
12446
12617
|
) + "\n";
|
|
12447
12618
|
}
|
|
12448
12619
|
function workspaceTsconfigJson(targetPath, workspaceRoot) {
|
|
12449
|
-
const rel =
|
|
12620
|
+
const rel = relative4(targetPath, join28(workspaceRoot, "tsconfig.base.json")).replace(/\\/g, "/");
|
|
12450
12621
|
return JSON.stringify(
|
|
12451
12622
|
{
|
|
12452
12623
|
extends: rel.startsWith(".") ? rel : `./${rel}`,
|
|
@@ -12522,10 +12693,10 @@ dist/
|
|
|
12522
12693
|
`;
|
|
12523
12694
|
}
|
|
12524
12695
|
function linkLocalPackagesForNoInstall(targetPath, localPackagesDir) {
|
|
12525
|
-
const nm =
|
|
12696
|
+
const nm = join28(targetPath, "node_modules");
|
|
12526
12697
|
mkdirSync8(nm, { recursive: true });
|
|
12527
|
-
const dest =
|
|
12528
|
-
if (!
|
|
12698
|
+
const dest = join28(nm, "@s2script");
|
|
12699
|
+
if (!existsSync20(dest)) symlinkSync(localPackagesDir, dest);
|
|
12529
12700
|
}
|
|
12530
12701
|
function runInstall(dir, pm) {
|
|
12531
12702
|
if (pm === "none") return;
|
|
@@ -12554,7 +12725,7 @@ async function createPlugin(opts = {}) {
|
|
|
12554
12725
|
);
|
|
12555
12726
|
}
|
|
12556
12727
|
let slug = workspaceRoot !== void 0 && opts.path !== void 0 ? assertBareSlug(opts.path) : opts.path;
|
|
12557
|
-
let targetPath = workspaceRoot === void 0 ? resolve23(opts.path ?? ".") : slug === void 0 ? void 0 :
|
|
12728
|
+
let targetPath = workspaceRoot === void 0 ? resolve23(opts.path ?? ".") : slug === void 0 ? void 0 : join28(workspaceRoot, "plugins", slug);
|
|
12558
12729
|
if (targetPath !== void 0) assertEmptyTarget(targetPath);
|
|
12559
12730
|
if (interactive) {
|
|
12560
12731
|
intro2("Create an s2script plugin");
|
|
@@ -12564,7 +12735,7 @@ async function createPlugin(opts = {}) {
|
|
|
12564
12735
|
slug = assertBareSlug(
|
|
12565
12736
|
await text2({ message: "Plugin name (directory under plugins/)", placeholder: "myplugin" })
|
|
12566
12737
|
);
|
|
12567
|
-
targetPath =
|
|
12738
|
+
targetPath = join28(workspaceRoot, "plugins", slug);
|
|
12568
12739
|
assertEmptyTarget(targetPath);
|
|
12569
12740
|
}
|
|
12570
12741
|
}
|
|
@@ -12627,37 +12798,37 @@ async function createPlugin(opts = {}) {
|
|
|
12627
12798
|
install = workspaceRoot !== void 0 ? "none" : install ?? (opts.noInstall ? "none" : "npm");
|
|
12628
12799
|
const finalTargetPath = targetPath;
|
|
12629
12800
|
const localPackagesDir = workspaceRoot === void 0 ? findLocalPackagesDir() : void 0;
|
|
12630
|
-
mkdirSync8(
|
|
12801
|
+
mkdirSync8(join28(finalTargetPath, "src"), { recursive: true });
|
|
12631
12802
|
if (workspaceRoot !== void 0) {
|
|
12632
|
-
writeFileSync16(
|
|
12803
|
+
writeFileSync16(join28(finalTargetPath, "package.json"), minimalPackageJsonContent(name));
|
|
12633
12804
|
writeFileSync16(
|
|
12634
|
-
|
|
12805
|
+
join28(finalTargetPath, "tsconfig.json"),
|
|
12635
12806
|
workspaceTsconfigJson(finalTargetPath, workspaceRoot)
|
|
12636
12807
|
);
|
|
12637
12808
|
} else if (kind === "library") {
|
|
12638
12809
|
const version = readCliVersion();
|
|
12639
12810
|
writeFileSync16(
|
|
12640
|
-
|
|
12811
|
+
join28(finalTargetPath, "package.json"),
|
|
12641
12812
|
libraryPackageJsonContent(name, game, version, localPackagesDir)
|
|
12642
12813
|
);
|
|
12643
|
-
writeFileSync16(
|
|
12644
|
-
writeFileSync16(
|
|
12814
|
+
writeFileSync16(join28(finalTargetPath, "tsconfig.json"), tsconfigJson());
|
|
12815
|
+
writeFileSync16(join28(finalTargetPath, "eslint.config.mjs"), eslintConfig());
|
|
12645
12816
|
} else {
|
|
12646
12817
|
const version = readCliVersion();
|
|
12647
12818
|
writeFileSync16(
|
|
12648
|
-
|
|
12819
|
+
join28(finalTargetPath, "package.json"),
|
|
12649
12820
|
packageJsonContent(name, game, version, localPackagesDir)
|
|
12650
12821
|
);
|
|
12651
|
-
writeFileSync16(
|
|
12652
|
-
writeFileSync16(
|
|
12822
|
+
writeFileSync16(join28(finalTargetPath, "tsconfig.json"), tsconfigJson());
|
|
12823
|
+
writeFileSync16(join28(finalTargetPath, "eslint.config.mjs"), eslintConfig());
|
|
12653
12824
|
}
|
|
12654
12825
|
if (kind === "library") {
|
|
12655
|
-
writeFileSync16(
|
|
12656
|
-
writeFileSync16(
|
|
12826
|
+
writeFileSync16(join28(finalTargetPath, "src", "index.ts"), LIBRARY_ENTRY);
|
|
12827
|
+
writeFileSync16(join28(finalTargetPath, "src", "index.d.ts"), LIBRARY_TYPES);
|
|
12657
12828
|
} else {
|
|
12658
|
-
writeFileSync16(
|
|
12829
|
+
writeFileSync16(join28(finalTargetPath, "src", "plugin.ts"), pluginSource(game));
|
|
12659
12830
|
}
|
|
12660
|
-
writeFileSync16(
|
|
12831
|
+
writeFileSync16(join28(finalTargetPath, ".gitignore"), gitignore());
|
|
12661
12832
|
let installed = false;
|
|
12662
12833
|
if (workspaceRoot === void 0) {
|
|
12663
12834
|
if (install !== "none") {
|
|
@@ -12685,7 +12856,7 @@ async function createPlugin(opts = {}) {
|
|
|
12685
12856
|
|
|
12686
12857
|
// src/create/workspace.ts
|
|
12687
12858
|
import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync17 } from "node:fs";
|
|
12688
|
-
import { join as
|
|
12859
|
+
import { join as join29, resolve as resolve24 } from "node:path";
|
|
12689
12860
|
var ROOT_DEFAULT_GAME = "cs2";
|
|
12690
12861
|
var CHANGESETS_CLI_RANGE = "^2.29.5";
|
|
12691
12862
|
function defaultWorkspaceName(dir) {
|
|
@@ -12769,14 +12940,14 @@ async function createWorkspace(opts = {}) {
|
|
|
12769
12940
|
name = name ?? defaultWorkspaceName(targetPath);
|
|
12770
12941
|
const version = readCliVersion();
|
|
12771
12942
|
const localPackagesDir = findLocalPackagesDir();
|
|
12772
|
-
mkdirSync9(
|
|
12773
|
-
mkdirSync9(
|
|
12774
|
-
mkdirSync9(
|
|
12775
|
-
writeFileSync17(
|
|
12776
|
-
writeFileSync17(
|
|
12777
|
-
writeFileSync17(
|
|
12778
|
-
writeFileSync17(
|
|
12779
|
-
writeFileSync17(
|
|
12943
|
+
mkdirSync9(join29(targetPath, "plugins"), { recursive: true });
|
|
12944
|
+
mkdirSync9(join29(targetPath, "packages"), { recursive: true });
|
|
12945
|
+
mkdirSync9(join29(targetPath, ".changeset"), { recursive: true });
|
|
12946
|
+
writeFileSync17(join29(targetPath, "package.json"), rootPackageJsonContent(name, version, localPackagesDir));
|
|
12947
|
+
writeFileSync17(join29(targetPath, "tsconfig.base.json"), tsconfigBaseJson());
|
|
12948
|
+
writeFileSync17(join29(targetPath, "eslint.config.mjs"), eslintConfig());
|
|
12949
|
+
writeFileSync17(join29(targetPath, ".changeset", "config.json"), changesetConfigJson());
|
|
12950
|
+
writeFileSync17(join29(targetPath, ".gitignore"), gitignore());
|
|
12780
12951
|
return { dir: targetPath, name };
|
|
12781
12952
|
}
|
|
12782
12953
|
|
|
@@ -13012,8 +13183,8 @@ async function run7(argv2) {
|
|
|
13012
13183
|
}
|
|
13013
13184
|
|
|
13014
13185
|
// src/config/gen.ts
|
|
13015
|
-
import { readFileSync as
|
|
13016
|
-
import { join as
|
|
13186
|
+
import { readFileSync as readFileSync25, writeFileSync as writeFileSync18, mkdirSync as mkdirSync10 } from "node:fs";
|
|
13187
|
+
import { join as join30 } from "node:path";
|
|
13017
13188
|
|
|
13018
13189
|
// src/config/config-path.ts
|
|
13019
13190
|
function configFileName(id) {
|
|
@@ -13060,12 +13231,12 @@ function genConfigFromManifest(manifest, outDir) {
|
|
|
13060
13231
|
const id = typeof manifest.id === "string" ? manifest.id : "";
|
|
13061
13232
|
if (!id) throw new Error("config gen: manifest declares config but has no id");
|
|
13062
13233
|
mkdirSync10(outDir, { recursive: true });
|
|
13063
|
-
const path2 =
|
|
13234
|
+
const path2 = join30(outDir, configFileName(id));
|
|
13064
13235
|
writeFileSync18(path2, generateDefaultJsonc(config));
|
|
13065
13236
|
return path2;
|
|
13066
13237
|
}
|
|
13067
13238
|
function genConfigForS2sp(s2spPath, outDir) {
|
|
13068
|
-
const entry = unzipSync(
|
|
13239
|
+
const entry = unzipSync(readFileSync25(s2spPath))["manifest.json"];
|
|
13069
13240
|
if (!entry) throw new Error(`config gen: ${s2spPath} has no manifest.json`);
|
|
13070
13241
|
const manifest = JSON.parse(Buffer.from(entry).toString("utf8"));
|
|
13071
13242
|
return genConfigFromManifest(manifest, outDir);
|
|
@@ -13112,12 +13283,12 @@ async function run8(argv2) {
|
|
|
13112
13283
|
}
|
|
13113
13284
|
|
|
13114
13285
|
// src/commands/codegen.ts
|
|
13115
|
-
import { dirname as dirname9, join as
|
|
13286
|
+
import { dirname as dirname9, join as join35 } from "node:path";
|
|
13116
13287
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
13117
13288
|
|
|
13118
13289
|
// src/schemagen/gen.ts
|
|
13119
|
-
import { readFileSync as
|
|
13120
|
-
import { join as
|
|
13290
|
+
import { readFileSync as readFileSync26, writeFileSync as writeFileSync19 } from "node:fs";
|
|
13291
|
+
import { join as join31 } from "node:path";
|
|
13121
13292
|
|
|
13122
13293
|
// src/schemagen/model.ts
|
|
13123
13294
|
function enumMemberNames(enumName, members) {
|
|
@@ -13422,7 +13593,7 @@ function emitDts(model) {
|
|
|
13422
13593
|
return id ? `${id} | null` : TSTYPE[f.accessorKind];
|
|
13423
13594
|
};
|
|
13424
13595
|
const names = new Set(model.classes.map((c2) => c2.className));
|
|
13425
|
-
const out = [HEADER2, 'import type { EntityRef } from "@s2script/sdk/entity";'];
|
|
13596
|
+
const out = [HEADER2, 'import type { EntityRef } from "@s2script/sdk/entity";', 'import type { Ptr } from "@s2script/sdk/unsafe";'];
|
|
13426
13597
|
const vecClasses = /* @__PURE__ */ new Set();
|
|
13427
13598
|
for (const c2 of model.classes) for (const f of c2.ownFields) {
|
|
13428
13599
|
const vi = VEC_INFO[f.accessorKind];
|
|
@@ -13484,16 +13655,67 @@ function emitDts(model) {
|
|
|
13484
13655
|
" * fields.glow.glowing = true;",
|
|
13485
13656
|
" */",
|
|
13486
13657
|
"export declare function wrapEntity<K extends keyof SchemaClasses>(className: K, ref: EntityRef): SchemaClasses[K];",
|
|
13658
|
+
"",
|
|
13659
|
+
"/**",
|
|
13660
|
+
" * A view factory for a raw address: the same field accessors as {@link wrapEntity}, over a `Ptr`",
|
|
13661
|
+
" * from `@s2script/sdk/unsafe` instead of a checked entity reference.",
|
|
13662
|
+
" *",
|
|
13663
|
+
" * UNSAFE. Nothing checks that the address still holds this class; a stale one reads garbage or",
|
|
13664
|
+
" * crashes. Use it for memory an engine call handed you, not for entities you can reference safely.",
|
|
13665
|
+
" *",
|
|
13666
|
+
" * @example",
|
|
13667
|
+
' * import { Ptr } from "@s2script/sdk/unsafe";',
|
|
13668
|
+
' * const fields = Ptr.from(pawn)?.as(structView("CCSPlayerPawn"));',
|
|
13669
|
+
" */",
|
|
13670
|
+
"export declare function structView<K extends keyof SchemaClasses>(className: K): (ptr: Ptr) => SchemaClasses[K];",
|
|
13487
13671
|
""
|
|
13488
13672
|
);
|
|
13489
13673
|
return out.join("\n");
|
|
13490
13674
|
}
|
|
13491
13675
|
|
|
13676
|
+
// src/schemagen/offset-slots.ts
|
|
13677
|
+
var S = JSON.stringify;
|
|
13678
|
+
var OffsetSlots = class {
|
|
13679
|
+
constructor() {
|
|
13680
|
+
this.index = /* @__PURE__ */ new Map();
|
|
13681
|
+
}
|
|
13682
|
+
/** The JS expression yielding the offset of `cls::field` (or -1 while it does not resolve). */
|
|
13683
|
+
expr(cls, field) {
|
|
13684
|
+
const key = `${cls}\0${field}`;
|
|
13685
|
+
let i2 = this.index.get(key);
|
|
13686
|
+
if (i2 === void 0) {
|
|
13687
|
+
i2 = this.index.size;
|
|
13688
|
+
this.index.set(key, i2);
|
|
13689
|
+
}
|
|
13690
|
+
return `(O[${i2}] >= 0 ? O[${i2}] : (O[${i2}] = off(${S(cls)},${S(field)})))`;
|
|
13691
|
+
}
|
|
13692
|
+
/** The declaration of the slot table; emit it once, before any accessor can run. */
|
|
13693
|
+
declaration() {
|
|
13694
|
+
return ` var O = new Int32Array(${Math.max(this.index.size, 1)}).fill(-1);`;
|
|
13695
|
+
}
|
|
13696
|
+
};
|
|
13697
|
+
|
|
13698
|
+
// src/schemagen/shared-module.ts
|
|
13699
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
13700
|
+
function sharedModule(header, name, body, bind) {
|
|
13701
|
+
const hash = createHash5("sha256").update(body.join("\n")).digest("hex").slice(0, 16);
|
|
13702
|
+
return [
|
|
13703
|
+
header,
|
|
13704
|
+
"(function () {",
|
|
13705
|
+
' var shared = typeof __s2_shared_module === "function" ? __s2_shared_module : function (key, factory) { return factory(); };',
|
|
13706
|
+
` var M = shared(${JSON.stringify(`${name}:${hash}`)}, function () {`,
|
|
13707
|
+
...body.map((line) => line === "" ? line : ` ${line}`),
|
|
13708
|
+
" });",
|
|
13709
|
+
...bind.map((line) => ` ${line}`),
|
|
13710
|
+
"})();"
|
|
13711
|
+
].join("\n");
|
|
13712
|
+
}
|
|
13713
|
+
|
|
13492
13714
|
// src/schemagen/emit-js.ts
|
|
13493
13715
|
var HEADER3 = "// GENERATED by `s2script gen-schema` from schema-catalog.json \u2014 DO NOT EDIT.";
|
|
13494
|
-
var
|
|
13495
|
-
function resolveExpr(f) {
|
|
13496
|
-
const base =
|
|
13716
|
+
var S2 = JSON.stringify;
|
|
13717
|
+
function resolveExpr(slots, f) {
|
|
13718
|
+
const base = slots.expr(f.declaringClass, f.rawName);
|
|
13497
13719
|
return f.addOffset ? `${base} + ${f.addOffset}` : base;
|
|
13498
13720
|
}
|
|
13499
13721
|
function accessorEntry(f, resolve29, guard2) {
|
|
@@ -13506,7 +13728,7 @@ function accessorEntry(f, resolve29, guard2) {
|
|
|
13506
13728
|
entry = `get: function () { ${g}var v = this.ref.${READ[f.accessorKind]}(${resolve29}); return v === null ? null : v.toString(); }`;
|
|
13507
13729
|
} else if (VEC_INFO[f.accessorKind]) {
|
|
13508
13730
|
const vi = VEC_INFO[f.accessorKind];
|
|
13509
|
-
entry = `get: function () { ${g}
|
|
13731
|
+
entry = `get: function () { ${g}return this.ref.read${vi.cls}(${resolve29}); }`;
|
|
13510
13732
|
} else {
|
|
13511
13733
|
entry = `get: function () { ${g}return this.ref.${READ[f.accessorKind]}(${resolve29}); }`;
|
|
13512
13734
|
}
|
|
@@ -13517,48 +13739,42 @@ function accessorEntry(f, resolve29, guard2) {
|
|
|
13517
13739
|
return entry;
|
|
13518
13740
|
}
|
|
13519
13741
|
function emitJs(model) {
|
|
13520
|
-
const
|
|
13521
|
-
const
|
|
13522
|
-
for (const c2 of model.classes) for (const f of c2.ownFields) {
|
|
13523
|
-
const vi = VEC_INFO[f.accessorKind];
|
|
13524
|
-
if (vi) vecClasses.add(vi.cls);
|
|
13525
|
-
}
|
|
13526
|
-
for (const cls of [...vecClasses].sort()) {
|
|
13527
|
-
out.push(` var ${cls} = __s2require("@s2script/sdk/math").${cls};`);
|
|
13528
|
-
}
|
|
13742
|
+
const slots = new OffsetSlots();
|
|
13743
|
+
const out = [" var off = __s2_schema_offset;", " var A = {};", " var E = {};"];
|
|
13529
13744
|
for (const c2 of model.classes) {
|
|
13530
|
-
out.push(` A[${
|
|
13745
|
+
out.push(` A[${S2(c2.className)}] = {`);
|
|
13531
13746
|
for (const f of c2.ownFields) {
|
|
13532
|
-
const entry = accessorEntry(f, resolveExpr(f), "");
|
|
13533
|
-
out.push(` ${
|
|
13747
|
+
const entry = accessorEntry(f, resolveExpr(slots, f), "");
|
|
13748
|
+
out.push(` ${S2(f.propName)}: { ${entry} },`);
|
|
13534
13749
|
}
|
|
13535
13750
|
for (const f of c2.embeddedFields) {
|
|
13536
|
-
out.push(` ${
|
|
13751
|
+
out.push(` ${S2(f.propName)}: { get: function () { return embed(${S2(f.embeddedClass)}, this.ref, ${slots.expr(f.declaringClass, f.rawName)}); } },`);
|
|
13537
13752
|
}
|
|
13538
13753
|
out.push(" };");
|
|
13539
13754
|
}
|
|
13540
13755
|
for (const e of model.embedded) {
|
|
13541
|
-
out.push(` E[${
|
|
13756
|
+
out.push(` E[${S2(e.className)}] = {`);
|
|
13542
13757
|
for (const f of e.fields) {
|
|
13543
|
-
const sub =
|
|
13758
|
+
const sub = slots.expr(f.declaringClass, f.rawName);
|
|
13544
13759
|
const resolve29 = f.addOffset ? `this.base + ${sub} + ${f.addOffset}` : `this.base + ${sub}`;
|
|
13545
13760
|
const guard2 = `if (this.base < 0 || ${sub} < 0) return null;`;
|
|
13546
|
-
out.push(` ${
|
|
13761
|
+
out.push(` ${S2(f.propName)}: { ${accessorEntry(f, resolve29, guard2)} },`);
|
|
13547
13762
|
}
|
|
13548
13763
|
for (const f of e.embeddedFields) {
|
|
13549
|
-
const sub =
|
|
13550
|
-
out.push(` ${
|
|
13764
|
+
const sub = slots.expr(f.declaringClass, f.rawName);
|
|
13765
|
+
out.push(` ${S2(f.propName)}: { get: function () { var s = ${sub}; return embed(${S2(f.embeddedClass)}, this.ref, (this.base < 0 || s < 0) ? -1 : this.base + s); } },`);
|
|
13551
13766
|
}
|
|
13552
13767
|
out.push(" };");
|
|
13553
13768
|
}
|
|
13769
|
+
out.push(slots.declaration());
|
|
13554
13770
|
out.push(" var P = {");
|
|
13555
|
-
for (const c2 of model.classes) if (c2.parent) out.push(` ${
|
|
13771
|
+
for (const c2 of model.classes) if (c2.parent) out.push(` ${S2(c2.className)}: ${S2(c2.parent)},`);
|
|
13556
13772
|
out.push(" };");
|
|
13557
13773
|
if (model.enums.length > 0) {
|
|
13558
13774
|
out.push(" var E_CONST = {};");
|
|
13559
13775
|
for (const e of model.enums) {
|
|
13560
|
-
const body = e.members.map((m) => `${
|
|
13561
|
-
out.push(` E_CONST[${
|
|
13776
|
+
const body = e.members.map((m) => `${S2(m.name)}: ${m.value}`).join(", ");
|
|
13777
|
+
out.push(` E_CONST[${S2(e.tsName)}] = Object.freeze({ ${body} });`);
|
|
13562
13778
|
}
|
|
13563
13779
|
}
|
|
13564
13780
|
out.push(
|
|
@@ -13575,21 +13791,42 @@ function emitJs(model) {
|
|
|
13575
13791
|
" Object.defineProperty(proto, name, { get: defs[name].get, set: defs[name].set, enumerable: true, configurable: true });",
|
|
13576
13792
|
" }",
|
|
13577
13793
|
" }",
|
|
13794
|
+
" return proto;",
|
|
13578
13795
|
" }",
|
|
13579
|
-
"
|
|
13796
|
+
" // One prototype per class, built on first use. A view is then one small object holding its",
|
|
13797
|
+
" // ref (and, embedded, its base offset): the accessors live on the shared prototype, where V8",
|
|
13798
|
+
" // keeps them on the fast path, instead of being redefined on every wrap and every embedded read.",
|
|
13799
|
+
" var PROTO = {}, EPROTO = {}, VIEW = {};",
|
|
13800
|
+
" function protoOf(className) {",
|
|
13801
|
+
" var p = PROTO[className];",
|
|
13802
|
+
" if (p === undefined) { p = Object.freeze(applyAccessors({}, className)); PROTO[className] = p; }",
|
|
13803
|
+
" return p;",
|
|
13804
|
+
" }",
|
|
13805
|
+
" function wrap(className, ref) { var o = Object.create(protoOf(className)); o.ref = ref; return o; }",
|
|
13580
13806
|
" function embed(className, ref, base) {",
|
|
13581
|
-
" var
|
|
13582
|
-
" if (
|
|
13583
|
-
"
|
|
13807
|
+
" var p = EPROTO[className];",
|
|
13808
|
+
" if (p === undefined) {",
|
|
13809
|
+
" p = {}; var defs = E[className];",
|
|
13810
|
+
" if (defs) for (var name in defs) {",
|
|
13811
|
+
" Object.defineProperty(p, name, { get: defs[name].get, set: defs[name].set, enumerable: true, configurable: true });",
|
|
13812
|
+
" }",
|
|
13813
|
+
" EPROTO[className] = p = Object.freeze(p);",
|
|
13584
13814
|
" }",
|
|
13585
|
-
" return o;",
|
|
13815
|
+
" var o = Object.create(p); o.ref = ref; o.base = base; return o;",
|
|
13586
13816
|
" }",
|
|
13587
|
-
"
|
|
13588
|
-
"
|
|
13589
|
-
"
|
|
13590
|
-
"
|
|
13817
|
+
" // A view factory for `Ptr.as`: the same accessors over a raw address, unchecked.",
|
|
13818
|
+
" function structView(className) {",
|
|
13819
|
+
" var v = VIEW[className];",
|
|
13820
|
+
" if (v === undefined) { v = Object.freeze(function (ptr) { return wrap(className, ptr); }); VIEW[className] = v; }",
|
|
13821
|
+
" return v;",
|
|
13822
|
+
" }",
|
|
13823
|
+
" return { applyAccessors: applyAccessors, wrap: wrap, structView: structView, enums: " + (model.enums.length > 0 ? "E_CONST" : "{}") + " };"
|
|
13591
13824
|
);
|
|
13592
|
-
return
|
|
13825
|
+
return sharedModule(HEADER3, "@s2script/cs2/schema", out, [
|
|
13826
|
+
"globalThis.__s2pkg_cs2_schema = { applyAccessors: M.applyAccessors, wrap: M.wrap };",
|
|
13827
|
+
"// Merge (not overwrite): this prelude runs FIRST, and pawn.js merges onto whatever it finds.",
|
|
13828
|
+
"globalThis.__s2pkg_cs2 = Object.assign({}, globalThis.__s2pkg_cs2, { wrapEntity: M.wrap, structView: M.structView }, M.enums);"
|
|
13829
|
+
]);
|
|
13593
13830
|
}
|
|
13594
13831
|
|
|
13595
13832
|
// src/schemagen/gen.ts
|
|
@@ -13600,16 +13837,16 @@ var EMBED_PATH = "games/cs2/codegen-embedded.json";
|
|
|
13600
13837
|
var JS_OUT = "games/cs2/js/schema.generated.js";
|
|
13601
13838
|
var DTS_OUT = "packages/cs2/schema.generated.d.ts";
|
|
13602
13839
|
function runGenSchema(repoRoot2, opts) {
|
|
13603
|
-
const catalog = JSON.parse(
|
|
13604
|
-
const list = JSON.parse(
|
|
13840
|
+
const catalog = JSON.parse(readFileSync26(join31(repoRoot2, CATALOG_PATH), "utf8"));
|
|
13841
|
+
const list = JSON.parse(readFileSync26(join31(repoRoot2, LIST_PATH), "utf8"));
|
|
13605
13842
|
let embed = [];
|
|
13606
13843
|
try {
|
|
13607
|
-
embed = JSON.parse(
|
|
13844
|
+
embed = JSON.parse(readFileSync26(join31(repoRoot2, EMBED_PATH), "utf8"));
|
|
13608
13845
|
} catch {
|
|
13609
13846
|
}
|
|
13610
13847
|
let enumCatalog = {};
|
|
13611
13848
|
try {
|
|
13612
|
-
enumCatalog = JSON.parse(
|
|
13849
|
+
enumCatalog = JSON.parse(readFileSync26(join31(repoRoot2, ENUMS_PATH), "utf8"));
|
|
13613
13850
|
} catch {
|
|
13614
13851
|
}
|
|
13615
13852
|
const model = buildModel(catalog, list, embed, enumCatalog);
|
|
@@ -13620,11 +13857,11 @@ function runGenSchema(repoRoot2, opts) {
|
|
|
13620
13857
|
const drift = [];
|
|
13621
13858
|
const files = [[JS_OUT, js], [DTS_OUT, dts]];
|
|
13622
13859
|
for (const [rel, content] of files) {
|
|
13623
|
-
const abs =
|
|
13860
|
+
const abs = join31(repoRoot2, rel);
|
|
13624
13861
|
if (opts.check) {
|
|
13625
13862
|
let cur = "";
|
|
13626
13863
|
try {
|
|
13627
|
-
cur =
|
|
13864
|
+
cur = readFileSync26(abs, "utf8");
|
|
13628
13865
|
} catch {
|
|
13629
13866
|
}
|
|
13630
13867
|
if (cur !== content) drift.push(rel);
|
|
@@ -13639,8 +13876,8 @@ function runGenSchema(repoRoot2, opts) {
|
|
|
13639
13876
|
}
|
|
13640
13877
|
|
|
13641
13878
|
// src/eventgen/gen.ts
|
|
13642
|
-
import { readFileSync as
|
|
13643
|
-
import { join as
|
|
13879
|
+
import { readFileSync as readFileSync27, writeFileSync as writeFileSync20 } from "node:fs";
|
|
13880
|
+
import { join as join32 } from "node:path";
|
|
13644
13881
|
|
|
13645
13882
|
// src/eventgen/model.ts
|
|
13646
13883
|
var TYPE_TO_GETTER = {
|
|
@@ -13725,15 +13962,15 @@ function emitEventDts(model) {
|
|
|
13725
13962
|
var CATALOG_PATH2 = "games/cs2/gamedata/event-catalog.json";
|
|
13726
13963
|
var DTS_OUT2 = "packages/cs2/events.generated.d.ts";
|
|
13727
13964
|
function runGenEvents(repoRoot2, opts) {
|
|
13728
|
-
const catalog = JSON.parse(
|
|
13965
|
+
const catalog = JSON.parse(readFileSync27(join32(repoRoot2, CATALOG_PATH2), "utf8"));
|
|
13729
13966
|
const model = buildEventModel(catalog);
|
|
13730
13967
|
const dts = emitEventDts(model);
|
|
13731
13968
|
const drift = [];
|
|
13732
|
-
const abs =
|
|
13969
|
+
const abs = join32(repoRoot2, DTS_OUT2);
|
|
13733
13970
|
if (opts.check) {
|
|
13734
13971
|
let cur = "";
|
|
13735
13972
|
try {
|
|
13736
|
-
cur =
|
|
13973
|
+
cur = readFileSync27(abs, "utf8");
|
|
13737
13974
|
} catch {
|
|
13738
13975
|
}
|
|
13739
13976
|
if (cur !== dts) drift.push(DTS_OUT2);
|
|
@@ -13744,8 +13981,8 @@ function runGenEvents(repoRoot2, opts) {
|
|
|
13744
13981
|
}
|
|
13745
13982
|
|
|
13746
13983
|
// src/navgen/gen.ts
|
|
13747
|
-
import { readFileSync as
|
|
13748
|
-
import { join as
|
|
13984
|
+
import { readFileSync as readFileSync28, writeFileSync as writeFileSync21 } from "node:fs";
|
|
13985
|
+
import { join as join33 } from "node:path";
|
|
13749
13986
|
|
|
13750
13987
|
// src/navgen/model.ts
|
|
13751
13988
|
var SUPPORTED_NAV_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -13810,7 +14047,7 @@ function buildNavModel(config, catalog) {
|
|
|
13810
14047
|
|
|
13811
14048
|
// src/navgen/emit-js.ts
|
|
13812
14049
|
var HEADER5 = "// GENERATED by `s2script gen-nav` from nav-targets.json \u2014 DO NOT EDIT.";
|
|
13813
|
-
var
|
|
14050
|
+
var S3 = JSON.stringify;
|
|
13814
14051
|
var READ_VIA = {
|
|
13815
14052
|
f32: "readFloat32Via",
|
|
13816
14053
|
bool: "readBoolVia",
|
|
@@ -13827,17 +14064,8 @@ var WRITE_VIA = {
|
|
|
13827
14064
|
i32: "writeInt32Via"
|
|
13828
14065
|
};
|
|
13829
14066
|
function emitNavJs(model) {
|
|
13830
|
-
const
|
|
13831
|
-
const
|
|
13832
|
-
for (const w of model.wrappers) {
|
|
13833
|
-
for (const f of w.fields) {
|
|
13834
|
-
const vi = VEC_INFO[f.accessorKind];
|
|
13835
|
-
if (vi) vecClasses.add(vi.cls);
|
|
13836
|
-
}
|
|
13837
|
-
}
|
|
13838
|
-
for (const cls of [...vecClasses].sort()) {
|
|
13839
|
-
out.push(` var ${cls} = __s2require("@s2script/sdk/math").${cls};`);
|
|
13840
|
-
}
|
|
14067
|
+
const slots = new OffsetSlots();
|
|
14068
|
+
const out = [" var off = __s2_schema_offset;"];
|
|
13841
14069
|
for (const w of model.wrappers) {
|
|
13842
14070
|
out.push(` function ${w.wrapper}(root, path, base) { this.root = root; this.path = path; this.base = base; }`);
|
|
13843
14071
|
out.push(` ${w.wrapper}.prototype.notifyChanged = function () {`);
|
|
@@ -13845,7 +14073,7 @@ function emitNavJs(model) {
|
|
|
13845
14073
|
out.push(` };`);
|
|
13846
14074
|
out.push(` Object.defineProperties(${w.wrapper}.prototype, {`);
|
|
13847
14075
|
for (const f of w.fields) {
|
|
13848
|
-
const own =
|
|
14076
|
+
const own = slots.expr(f.declaringClass, f.rawName);
|
|
13849
14077
|
const withDelta = f.addOffset ? `${own} + ${f.addOffset}` : own;
|
|
13850
14078
|
const resolve29 = `${withDelta} + this.base`;
|
|
13851
14079
|
let getter;
|
|
@@ -13856,7 +14084,7 @@ function emitNavJs(model) {
|
|
|
13856
14084
|
getter = `get: function () { var v = this.root.readInt64Via(this.path, ${resolve29}); return v === null ? null : v.toString(); }`;
|
|
13857
14085
|
} else if (VEC_INFO[kind]) {
|
|
13858
14086
|
const vi = VEC_INFO[kind];
|
|
13859
|
-
getter = `get: function () {
|
|
14087
|
+
getter = `get: function () { return this.root.read${vi.cls}Chain(this.path, ${resolve29}); }`;
|
|
13860
14088
|
} else if (kind === "handle") {
|
|
13861
14089
|
getter = `get: function () { return this.root.readHandleVia(this.path, ${resolve29}); }`;
|
|
13862
14090
|
} else {
|
|
@@ -13866,9 +14094,10 @@ function emitNavJs(model) {
|
|
|
13866
14094
|
}
|
|
13867
14095
|
const wmethod = f.navWritable ? WRITE_VIA[kind] : void 0;
|
|
13868
14096
|
const setter = wmethod ? `, set: function (v) { this.root.${wmethod}(this.path, ${resolve29}, v); }` : "";
|
|
13869
|
-
out.push(` ${
|
|
14097
|
+
out.push(` ${S3(f.propName)}: { ${getter}${setter} },`);
|
|
13870
14098
|
}
|
|
13871
14099
|
out.push(" });");
|
|
14100
|
+
out.push(` Object.freeze(${w.wrapper}.prototype); Object.freeze(${w.wrapper});`);
|
|
13872
14101
|
}
|
|
13873
14102
|
const bySource = /* @__PURE__ */ new Map();
|
|
13874
14103
|
for (const w of model.wrappers) {
|
|
@@ -13877,20 +14106,20 @@ function emitNavJs(model) {
|
|
|
13877
14106
|
}
|
|
13878
14107
|
out.push(" function applyNav(proto, className) {");
|
|
13879
14108
|
for (const [src, wrappers] of [...bySource.entries()].sort((a2, b) => a2[0] < b[0] ? -1 : a2[0] > b[0] ? 1 : 0)) {
|
|
13880
|
-
out.push(` if (className === ${
|
|
14109
|
+
out.push(` if (className === ${S3(src)}) {`);
|
|
13881
14110
|
for (const w of wrappers) {
|
|
13882
|
-
out.push(` Object.defineProperty(proto, ${
|
|
14111
|
+
out.push(` Object.defineProperty(proto, ${S3(w.prop)}, {`);
|
|
13883
14112
|
out.push(` get: function () {`);
|
|
13884
14113
|
out.push(` var _p = [];`);
|
|
13885
14114
|
for (let i2 = 0; i2 < w.path.length; i2++) {
|
|
13886
14115
|
const h2 = w.path[i2];
|
|
13887
|
-
out.push(` var o${i2} =
|
|
14116
|
+
out.push(` var o${i2} = ${slots.expr(h2.cls, h2.field)}; if (o${i2} < 0) return null; _p.push(o${i2});`);
|
|
13888
14117
|
}
|
|
13889
14118
|
if (w.base.length > 0) {
|
|
13890
14119
|
out.push(` var _b = 0;`);
|
|
13891
14120
|
for (let i2 = 0; i2 < w.base.length; i2++) {
|
|
13892
14121
|
const h2 = w.base[i2];
|
|
13893
|
-
out.push(` var b${i2} =
|
|
14122
|
+
out.push(` var b${i2} = ${slots.expr(h2.cls, h2.field)}; if (b${i2} < 0) return null; _b += b${i2};`);
|
|
13894
14123
|
}
|
|
13895
14124
|
out.push(` return new ${w.wrapper}(this.ref, _p, _b);`);
|
|
13896
14125
|
} else {
|
|
@@ -13902,10 +14131,11 @@ function emitNavJs(model) {
|
|
|
13902
14131
|
out.push(" }");
|
|
13903
14132
|
}
|
|
13904
14133
|
out.push(" }");
|
|
13905
|
-
out.push(
|
|
13906
|
-
out.push("}
|
|
13907
|
-
|
|
13908
|
-
|
|
14134
|
+
out.push(slots.declaration());
|
|
14135
|
+
out.push(" return { applyNav: applyNav };");
|
|
14136
|
+
return sharedModule(HEADER5, "@s2script/cs2/nav", out, [
|
|
14137
|
+
"globalThis.__s2pkg_cs2_nav = { applyNav: M.applyNav };"
|
|
14138
|
+
]) + "\n";
|
|
13909
14139
|
}
|
|
13910
14140
|
|
|
13911
14141
|
// src/navgen/emit-dts.ts
|
|
@@ -13966,8 +14196,8 @@ var CATALOG_PATH3 = "games/cs2/gamedata/schema-catalog.json";
|
|
|
13966
14196
|
var JS_OUT2 = "games/cs2/js/nav.generated.js";
|
|
13967
14197
|
var DTS_OUT3 = "packages/cs2/nav.generated.d.ts";
|
|
13968
14198
|
function runGenNav(repoRoot2, opts) {
|
|
13969
|
-
const config = JSON.parse(
|
|
13970
|
-
const catalog = JSON.parse(
|
|
14199
|
+
const config = JSON.parse(readFileSync28(join33(repoRoot2, TARGETS_PATH), "utf8"));
|
|
14200
|
+
const catalog = JSON.parse(readFileSync28(join33(repoRoot2, CATALOG_PATH3), "utf8"));
|
|
13971
14201
|
const model = buildNavModel(config, catalog);
|
|
13972
14202
|
const js = emitNavJs(model);
|
|
13973
14203
|
const dts = emitNavDts(model);
|
|
@@ -13975,11 +14205,11 @@ function runGenNav(repoRoot2, opts) {
|
|
|
13975
14205
|
const drift = [];
|
|
13976
14206
|
const files = [[JS_OUT2, js], [DTS_OUT3, dts]];
|
|
13977
14207
|
for (const [rel, content] of files) {
|
|
13978
|
-
const abs =
|
|
14208
|
+
const abs = join33(repoRoot2, rel);
|
|
13979
14209
|
if (opts.check) {
|
|
13980
14210
|
let cur = "";
|
|
13981
14211
|
try {
|
|
13982
|
-
cur =
|
|
14212
|
+
cur = readFileSync28(abs, "utf8");
|
|
13983
14213
|
} catch {
|
|
13984
14214
|
}
|
|
13985
14215
|
if (cur !== content) drift.push(rel);
|
|
@@ -13991,22 +14221,22 @@ function runGenNav(repoRoot2, opts) {
|
|
|
13991
14221
|
}
|
|
13992
14222
|
|
|
13993
14223
|
// src/hookgen/gen.ts
|
|
13994
|
-
import { readFileSync as
|
|
13995
|
-
import { join as
|
|
14224
|
+
import { readFileSync as readFileSync29, writeFileSync as writeFileSync22 } from "node:fs";
|
|
14225
|
+
import { join as join34 } from "node:path";
|
|
13996
14226
|
var GAMEDATA_PATH = "games/cs2/gamedata/game.cs2.jsonc";
|
|
13997
14227
|
var DTS_OUT4 = "packages/cs2/hooks.generated.d.ts";
|
|
13998
14228
|
function runGenHooks(repoRoot2, opts) {
|
|
13999
|
-
const raw =
|
|
14229
|
+
const raw = readFileSync29(join34(repoRoot2, GAMEDATA_PATH), "utf8");
|
|
14000
14230
|
const gd = JSON.parse(stripJsonComments(raw));
|
|
14001
14231
|
const hooks = gd.hooks ?? {};
|
|
14002
14232
|
const model = buildHookModel(hooks);
|
|
14003
14233
|
const dts = emitHookDts(model);
|
|
14004
14234
|
const drift = [];
|
|
14005
|
-
const abs =
|
|
14235
|
+
const abs = join34(repoRoot2, DTS_OUT4);
|
|
14006
14236
|
if (opts.check) {
|
|
14007
14237
|
let cur = "";
|
|
14008
14238
|
try {
|
|
14009
|
-
cur =
|
|
14239
|
+
cur = readFileSync29(abs, "utf8");
|
|
14010
14240
|
} catch {
|
|
14011
14241
|
}
|
|
14012
14242
|
if (cur !== dts) drift.push(DTS_OUT4);
|
|
@@ -14019,7 +14249,7 @@ function runGenHooks(repoRoot2, opts) {
|
|
|
14019
14249
|
|
|
14020
14250
|
// src/commands/codegen.ts
|
|
14021
14251
|
function repoRoot() {
|
|
14022
|
-
return
|
|
14252
|
+
return join35(dirname9(fileURLToPath3(import.meta.url)), "..", "..", "..");
|
|
14023
14253
|
}
|
|
14024
14254
|
async function run9(kind, argv2) {
|
|
14025
14255
|
const root = repoRoot();
|
|
@@ -14076,9 +14306,9 @@ async function run9(kind, argv2) {
|
|
|
14076
14306
|
}
|
|
14077
14307
|
|
|
14078
14308
|
// src/commands/inspect.ts
|
|
14079
|
-
import { readFileSync as
|
|
14309
|
+
import { readFileSync as readFileSync30 } from "node:fs";
|
|
14080
14310
|
function inspectArchive(path2) {
|
|
14081
|
-
const files = unzipSync(
|
|
14311
|
+
const files = unzipSync(readFileSync30(path2));
|
|
14082
14312
|
if (!files["manifest.json"]) throw new Error(`${path2}: missing manifest.json`);
|
|
14083
14313
|
const manifest = JSON.parse(Buffer.from(files["manifest.json"]).toString("utf8"));
|
|
14084
14314
|
const lines = [`plugin: ${manifest.id ?? "(unknown)"}`];
|
|
@@ -14107,10 +14337,10 @@ async function run10(argv2) {
|
|
|
14107
14337
|
}
|
|
14108
14338
|
|
|
14109
14339
|
// src/engine-functions/migrate-v1.ts
|
|
14110
|
-
import { closeSync, existsSync as
|
|
14111
|
-
import { dirname as dirname10, isAbsolute as isAbsolute2, join as
|
|
14112
|
-
import { createHash as
|
|
14113
|
-
import
|
|
14340
|
+
import { closeSync, existsSync as existsSync21, linkSync, lstatSync as lstatSync2, mkdirSync as mkdirSync11, openSync, readFileSync as readFileSync31, readdirSync as readdirSync9, renameSync as renameSync4, unlinkSync, writeFileSync as writeFileSync23 } from "node:fs";
|
|
14341
|
+
import { dirname as dirname10, isAbsolute as isAbsolute2, join as join36, relative as relative5, resolve as resolve26, sep as sep6 } from "node:path";
|
|
14342
|
+
import { createHash as createHash6, randomUUID } from "node:crypto";
|
|
14343
|
+
import ts6 from "typescript";
|
|
14114
14344
|
var PLATFORM3 = "linuxsteamrt64";
|
|
14115
14345
|
var SCOPE = "structurally lossless conversion of declared v1 contract; native ABI completeness is not verified";
|
|
14116
14346
|
var IDENT = /^[A-Za-z_$][\w$]*$/;
|
|
@@ -14131,7 +14361,7 @@ function fields(value, allowed, where2, errors) {
|
|
|
14131
14361
|
for (const key of Object.keys(value)) if (!allowed.includes(key)) errors.push(`${where2}: unsupported field ${key}`);
|
|
14132
14362
|
}
|
|
14133
14363
|
function contained(dir, path2) {
|
|
14134
|
-
const r2 =
|
|
14364
|
+
const r2 = relative5(dir, path2);
|
|
14135
14365
|
return r2 === "" || r2 !== ".." && !r2.startsWith(`..${sep6}`) && !isAbsolute2(r2);
|
|
14136
14366
|
}
|
|
14137
14367
|
function targetOf(ref, signatures, where2, errors) {
|
|
@@ -14235,11 +14465,11 @@ function hookOf(name, value, signatures, errors) {
|
|
|
14235
14465
|
}
|
|
14236
14466
|
function sourceFiles(dir, pkg, errors) {
|
|
14237
14467
|
const result = /* @__PURE__ */ new Set();
|
|
14238
|
-
const src =
|
|
14468
|
+
const src = join36(dir, "src");
|
|
14239
14469
|
function walk(at) {
|
|
14240
|
-
if (!
|
|
14241
|
-
for (const item of
|
|
14242
|
-
const p =
|
|
14470
|
+
if (!existsSync21(at)) return;
|
|
14471
|
+
for (const item of readdirSync9(at, { withFileTypes: true })) {
|
|
14472
|
+
const p = join36(at, item.name);
|
|
14243
14473
|
if (item.isDirectory()) walk(p);
|
|
14244
14474
|
else if (item.isFile() && /\.[cm]?[jt]sx?$/.test(item.name)) result.add(p);
|
|
14245
14475
|
}
|
|
@@ -14247,23 +14477,23 @@ function sourceFiles(dir, pkg, errors) {
|
|
|
14247
14477
|
walk(src);
|
|
14248
14478
|
if (valid2(pkg.main)) {
|
|
14249
14479
|
const p = resolve26(dir, pkg.main);
|
|
14250
|
-
if (contained(dir, p) &&
|
|
14480
|
+
if (contained(dir, p) && existsSync21(p) && lstatSync2(p).isFile()) result.add(p);
|
|
14251
14481
|
}
|
|
14252
14482
|
const queue = [...result];
|
|
14253
14483
|
for (let i2 = 0; i2 < queue.length; i2++) {
|
|
14254
14484
|
const file = queue[i2];
|
|
14255
|
-
const ast =
|
|
14485
|
+
const ast = ts6.createSourceFile(file, readFileSync31(file, "utf8"), ts6.ScriptTarget.Latest, true);
|
|
14256
14486
|
const follow = (spec, node) => {
|
|
14257
14487
|
if (!spec.startsWith(".")) return;
|
|
14258
|
-
const at = `${
|
|
14488
|
+
const at = `${relative5(dir, file)}:${ast.getLineAndCharacterOfPosition(node.getStart(ast)).line + 1}`;
|
|
14259
14489
|
const base = resolve26(dirname10(file), spec);
|
|
14260
14490
|
if (!contained(dir, base)) {
|
|
14261
14491
|
errors.push(`${at}: local module ${JSON.stringify(spec)} escapes plugin directory`);
|
|
14262
14492
|
return;
|
|
14263
14493
|
}
|
|
14264
14494
|
const stem = base.replace(/\.[cm]?[jt]sx?$/, "");
|
|
14265
|
-
const candidates = [base, ...[".ts", ".tsx", ".js", ".jsx", ".mts", ".mjs", ".cts", ".cjs"].map((x) => stem + x), ...["index.ts", "index.tsx", "index.js", "index.jsx"].map((x) =>
|
|
14266
|
-
const found = candidates.find((p) => contained(dir, p) &&
|
|
14495
|
+
const candidates = [base, ...[".ts", ".tsx", ".js", ".jsx", ".mts", ".mjs", ".cts", ".cjs"].map((x) => stem + x), ...["index.ts", "index.tsx", "index.js", "index.jsx"].map((x) => join36(base, x))];
|
|
14496
|
+
const found = candidates.find((p) => contained(dir, p) && existsSync21(p) && lstatSync2(p).isFile());
|
|
14267
14497
|
if (!found) {
|
|
14268
14498
|
errors.push(`${at}: unresolved local module ${JSON.stringify(spec)}`);
|
|
14269
14499
|
return;
|
|
@@ -14273,18 +14503,18 @@ function sourceFiles(dir, pkg, errors) {
|
|
|
14273
14503
|
queue.push(found);
|
|
14274
14504
|
};
|
|
14275
14505
|
for (const statement of ast.statements) {
|
|
14276
|
-
if (!
|
|
14506
|
+
if (!ts6.isImportDeclaration(statement) && !ts6.isExportDeclaration(statement)) continue;
|
|
14277
14507
|
const spec = statement.moduleSpecifier;
|
|
14278
|
-
if (spec &&
|
|
14508
|
+
if (spec && ts6.isStringLiteral(spec)) follow(spec.text, spec);
|
|
14279
14509
|
}
|
|
14280
14510
|
const visit = (node) => {
|
|
14281
|
-
if (
|
|
14511
|
+
if (ts6.isCallExpression(node) && (ts6.isIdentifier(node.expression) && node.expression.text === "require" || node.expression.kind === ts6.SyntaxKind.ImportKeyword)) {
|
|
14282
14512
|
const arg = node.arguments[0];
|
|
14283
|
-
if (!arg || !
|
|
14284
|
-
errors.push(`${
|
|
14513
|
+
if (!arg || !ts6.isStringLiteral(arg) && !ts6.isNoSubstitutionTemplateLiteral(arg)) {
|
|
14514
|
+
errors.push(`${relative5(dir, file)}:${ast.getLineAndCharacterOfPosition(node.getStart(ast)).line + 1}: dynamic module edge cannot be resolved for source analysis`);
|
|
14285
14515
|
} else follow(arg.text, node);
|
|
14286
14516
|
}
|
|
14287
|
-
|
|
14517
|
+
ts6.forEachChild(node, visit);
|
|
14288
14518
|
};
|
|
14289
14519
|
visit(ast);
|
|
14290
14520
|
}
|
|
@@ -14293,152 +14523,152 @@ function sourceFiles(dir, pkg, errors) {
|
|
|
14293
14523
|
function scanSource(files, calls, hooks, report) {
|
|
14294
14524
|
const namespaces = new Set(hooks.values());
|
|
14295
14525
|
for (const file of files) {
|
|
14296
|
-
const source =
|
|
14297
|
-
if (source.parseDiagnostics?.length) report.ambiguities.push(`${
|
|
14526
|
+
const source = ts6.createSourceFile(file, readFileSync31(file, "utf8"), ts6.ScriptTarget.Latest, true);
|
|
14527
|
+
if (source.parseDiagnostics?.length) report.ambiguities.push(`${relative5(report.package, file)}: source syntax errors prevent reliable reference analysis`);
|
|
14298
14528
|
const ambiguity = (node, message) => {
|
|
14299
|
-
report.ambiguities.push(`${
|
|
14529
|
+
report.ambiguities.push(`${relative5(report.package, file)}:${source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1}: ${message}`);
|
|
14300
14530
|
};
|
|
14301
14531
|
const visit = (node) => {
|
|
14302
|
-
if ((
|
|
14532
|
+
if ((ts6.isImportDeclaration(node) || ts6.isExportDeclaration(node)) && node.moduleSpecifier && ts6.isStringLiteral(node.moduleSpecifier)) {
|
|
14303
14533
|
const spec = node.moduleSpecifier.text;
|
|
14304
14534
|
if (spec === "@s2script/sdk/unsafe") {
|
|
14305
|
-
if (
|
|
14535
|
+
if (ts6.isExportDeclaration(node)) ambiguity(node, "unsafe Engine reexport prevents proving legacy timing/null behavior");
|
|
14306
14536
|
else {
|
|
14307
|
-
const
|
|
14308
|
-
const defaultBinding =
|
|
14309
|
-
if (node.importClause?.name ||
|
|
14537
|
+
const bindings2 = node.importClause?.namedBindings;
|
|
14538
|
+
const defaultBinding = bindings2 && ts6.isNamedImports(bindings2) && bindings2.elements.some((e) => (e.propertyName?.text ?? e.name.text) === "default");
|
|
14539
|
+
if (node.importClause?.name || bindings2 && ts6.isNamespaceImport(bindings2) || defaultBinding) {
|
|
14310
14540
|
ambiguity(node, "indirect Engine namespace import from unsafe SDK prevents proving legacy timing/null behavior");
|
|
14311
14541
|
}
|
|
14312
14542
|
}
|
|
14313
14543
|
}
|
|
14314
|
-
if (["node:module", "module"].includes(spec) && (
|
|
14315
|
-
ambiguity(node,
|
|
14544
|
+
if (["node:module", "module"].includes(spec) && (ts6.isExportDeclaration(node) || node.importClause)) {
|
|
14545
|
+
ambiguity(node, ts6.isExportDeclaration(node) ? "module loader reexport prevents complete local source analysis" : "indirect module loader import prevents complete local source analysis");
|
|
14316
14546
|
}
|
|
14317
14547
|
}
|
|
14318
|
-
if (
|
|
14548
|
+
if (ts6.isImportEqualsDeclaration(node) && !node.isTypeOnly && ts6.isExternalModuleReference(node.moduleReference)) {
|
|
14319
14549
|
const ref = node.moduleReference.expression;
|
|
14320
|
-
const spec = ref &&
|
|
14550
|
+
const spec = ref && ts6.isStringLiteral(ref) ? ref.text : void 0;
|
|
14321
14551
|
if (spec === "@s2script/sdk/unsafe") ambiguity(node, "unsafe Engine import-equals export or alias prevents proving legacy timing/null behavior");
|
|
14322
14552
|
else if (spec === "node:module" || spec === "module") ambiguity(node, "module loader import-equals export or alias prevents complete local source analysis");
|
|
14323
14553
|
else ambiguity(node, "import-equals module edge cannot be followed for complete source analysis");
|
|
14324
14554
|
}
|
|
14325
|
-
if (
|
|
14555
|
+
if (ts6.isImportSpecifier(node) && (node.propertyName?.text ?? node.name.text) === "createRequire") {
|
|
14326
14556
|
ambiguity(node, "indirect module loader factory prevents complete local source analysis");
|
|
14327
14557
|
}
|
|
14328
|
-
if (
|
|
14558
|
+
if (ts6.isCallExpression(node) && (ts6.isIdentifier(node.expression) && node.expression.text === "require" || node.expression.kind === ts6.SyntaxKind.ImportKeyword)) {
|
|
14329
14559
|
const arg = node.arguments[0];
|
|
14330
|
-
if (arg && (
|
|
14560
|
+
if (arg && (ts6.isStringLiteral(arg) || ts6.isNoSubstitutionTemplateLiteral(arg)) && arg.text === "@s2script/sdk/unsafe") {
|
|
14331
14561
|
ambiguity(node, "indirect Engine namespace load from unsafe SDK prevents proving legacy timing/null behavior");
|
|
14332
14562
|
}
|
|
14333
|
-
if (arg && (
|
|
14563
|
+
if (arg && (ts6.isStringLiteral(arg) || ts6.isNoSubstitutionTemplateLiteral(arg)) && ["node:module", "module"].includes(arg.text)) {
|
|
14334
14564
|
ambiguity(node, "indirect module loader import prevents complete local source analysis");
|
|
14335
14565
|
}
|
|
14336
14566
|
}
|
|
14337
|
-
if (
|
|
14567
|
+
if (ts6.isIdentifier(node) && node.text === "require") {
|
|
14338
14568
|
const parent = node.parent;
|
|
14339
|
-
const directCall =
|
|
14340
|
-
const declaredName = (
|
|
14341
|
-
const propertyName = (
|
|
14342
|
-
if (declaredName ||
|
|
14569
|
+
const directCall = ts6.isCallExpression(parent) && parent.expression === node;
|
|
14570
|
+
const declaredName = (ts6.isVariableDeclaration(parent) || ts6.isParameter(parent)) && parent.name === node;
|
|
14571
|
+
const propertyName = (ts6.isPropertyAccessExpression(parent) || ts6.isPropertyAssignment(parent)) && parent.name === node;
|
|
14572
|
+
if (declaredName || ts6.isImportSpecifier(parent)) ambiguity(node, "shadowed module loader binding prevents complete local source analysis");
|
|
14343
14573
|
else if (!directCall && !propertyName) ambiguity(node, "indirect module loader alias or escape prevents complete local source analysis");
|
|
14344
14574
|
}
|
|
14345
|
-
if (
|
|
14575
|
+
if (ts6.isIdentifier(node) && node.text === "createRequire") {
|
|
14346
14576
|
const parent = node.parent;
|
|
14347
|
-
if (!
|
|
14577
|
+
if (!ts6.isImportSpecifier(parent) && !((ts6.isVariableDeclaration(parent) || ts6.isParameter(parent)) && parent.name === node)) {
|
|
14348
14578
|
ambiguity(node, "indirect module loader factory prevents complete local source analysis");
|
|
14349
14579
|
}
|
|
14350
14580
|
}
|
|
14351
|
-
if (
|
|
14581
|
+
if (ts6.isIdentifier(node) && (node.text === "globalThis" || node.text === "global" || node.text === "module")) {
|
|
14352
14582
|
const parent = node.parent;
|
|
14353
|
-
const declaredName = (
|
|
14583
|
+
const declaredName = (ts6.isVariableDeclaration(parent) || ts6.isParameter(parent)) && parent.name === node;
|
|
14354
14584
|
if (!declaredName) {
|
|
14355
|
-
if (
|
|
14585
|
+
if (ts6.isPropertyAccessExpression(parent) && parent.expression === node) {
|
|
14356
14586
|
if (node.text !== "module" && parent.name.text === "Engine") ambiguity(parent, "indirect global Engine access prevents proving legacy timing/null behavior");
|
|
14357
14587
|
else if (parent.name.text === "require" || parent.name.text === "createRequire") ambiguity(parent, "indirect module loader access prevents complete local source analysis");
|
|
14358
14588
|
else if (node.text === "module" && parent.name.text !== "exports") ambiguity(parent, "indirect module loader or module escape prevents complete local source analysis");
|
|
14359
|
-
} else if (
|
|
14589
|
+
} else if (ts6.isElementAccessExpression(parent) && parent.expression === node) {
|
|
14360
14590
|
const key = parent.argumentExpression;
|
|
14361
|
-
const
|
|
14362
|
-
if (node.text !== "module" &&
|
|
14363
|
-
else if (
|
|
14364
|
-
else if (
|
|
14591
|
+
const literal2 = key && (ts6.isStringLiteral(key) || ts6.isNoSubstitutionTemplateLiteral(key)) ? key.text : void 0;
|
|
14592
|
+
if (node.text !== "module" && literal2 === "Engine") ambiguity(parent, "computed global Engine access prevents proving legacy timing/null behavior");
|
|
14593
|
+
else if (literal2 === "require" || literal2 === "createRequire" || node.text === "module") ambiguity(parent, "indirect module loader access prevents complete local source analysis");
|
|
14594
|
+
else if (literal2 === void 0) ambiguity(parent, "computed global access may hide Engine or a module loader");
|
|
14365
14595
|
} else ambiguity(node, `indirect ${node.text} escape may hide Engine or a module loader`);
|
|
14366
14596
|
}
|
|
14367
14597
|
}
|
|
14368
|
-
if (
|
|
14369
|
-
report.ambiguities.push(`${
|
|
14598
|
+
if (ts6.isImportSpecifier(node) && node.propertyName?.text === "Engine" && node.name.text !== "Engine") {
|
|
14599
|
+
report.ambiguities.push(`${relative5(report.package, file)}:${source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1}: imported Engine alias prevents proving legacy timing/null behavior`);
|
|
14370
14600
|
}
|
|
14371
|
-
if (
|
|
14372
|
-
report.ambiguities.push(`${
|
|
14601
|
+
if (ts6.isExportSpecifier(node) && (node.propertyName?.text ?? node.name.text) === "Engine") {
|
|
14602
|
+
report.ambiguities.push(`${relative5(report.package, file)}:${source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1}: exported Engine escape prevents proving legacy timing/null behavior`);
|
|
14373
14603
|
}
|
|
14374
|
-
if (
|
|
14375
|
-
report.ambiguities.push(`${
|
|
14604
|
+
if (ts6.isBindingElement(node) && node.propertyName && ts6.isIdentifier(node.propertyName) && node.propertyName.text === "Engine") {
|
|
14605
|
+
report.ambiguities.push(`${relative5(report.package, file)}:${source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1}: destructured Engine alias prevents proving legacy timing/null behavior`);
|
|
14376
14606
|
}
|
|
14377
|
-
if (
|
|
14378
|
-
report.ambiguities.push(`${
|
|
14607
|
+
if (ts6.isParameter(node) && hooks.size && ts6.isObjectBindingPattern(node.name) && node.name.elements.some((e) => namespaces.has(e.propertyName && ts6.isIdentifier(e.propertyName) ? e.propertyName.text : e.name.getText(source)))) {
|
|
14608
|
+
report.ambiguities.push(`${relative5(report.package, file)}:${source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1}: destructured ctx hook namespace alias prevents proving callback timing`);
|
|
14379
14609
|
}
|
|
14380
|
-
if (
|
|
14610
|
+
if (ts6.isIdentifier(node) && (node.text === "Engine" || node.text === "ctx")) {
|
|
14381
14611
|
const parent = node.parent;
|
|
14382
|
-
const declaration = (
|
|
14383
|
-
const importName =
|
|
14384
|
-
const propertyName = (
|
|
14385
|
-
if (!declaration && !importName && !propertyName && !(
|
|
14612
|
+
const declaration = (ts6.isVariableDeclaration(parent) || ts6.isParameter(parent) || ts6.isBindingElement(parent)) && parent.name === node;
|
|
14613
|
+
const importName = ts6.isImportSpecifier(parent) || ts6.isImportClause(parent) || ts6.isNamespaceImport(parent) || ts6.isExportSpecifier(parent);
|
|
14614
|
+
const propertyName = (ts6.isPropertyAccessExpression(parent) || ts6.isPropertyAssignment(parent)) && parent.name === node;
|
|
14615
|
+
if (!declaration && !importName && !propertyName && !(ts6.isElementAccessExpression(parent) && parent.expression === node)) {
|
|
14386
14616
|
let indirect = false;
|
|
14387
|
-
if (
|
|
14388
|
-
if (node.text === "Engine") indirect = !(["call", "hook"].includes(parent.name.text) &&
|
|
14617
|
+
if (ts6.isPropertyAccessExpression(parent) && parent.expression === node) {
|
|
14618
|
+
if (node.text === "Engine") indirect = !(["call", "hook"].includes(parent.name.text) && ts6.isCallExpression(parent.parent) && parent.parent.expression === parent);
|
|
14389
14619
|
else if (namespaces.has(parent.name.text)) {
|
|
14390
14620
|
const member = parent.parent;
|
|
14391
|
-
indirect = !(
|
|
14621
|
+
indirect = !(ts6.isPropertyAccessExpression(member) && member.expression === parent && hooks.get(member.name.text) === parent.name.text && ts6.isCallExpression(member.parent) && member.parent.expression === member);
|
|
14392
14622
|
}
|
|
14393
14623
|
} else indirect = node.text === "Engine" || hooks.size > 0;
|
|
14394
|
-
if (indirect) report.ambiguities.push(`${
|
|
14624
|
+
if (indirect) report.ambiguities.push(`${relative5(report.package, file)}:${source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1}: indirect ${node.text} alias or escape prevents proving legacy timing/null behavior`);
|
|
14395
14625
|
}
|
|
14396
14626
|
}
|
|
14397
|
-
if (
|
|
14627
|
+
if (ts6.isElementAccessExpression(node) && ts6.isIdentifier(node.expression) && node.expression.text === "Engine") {
|
|
14398
14628
|
const line = source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1;
|
|
14399
|
-
report.ambiguities.push(`${
|
|
14629
|
+
report.ambiguities.push(`${relative5(report.package, file)}:${line}: computed Engine lookup prevents proving timing/null behavior`);
|
|
14400
14630
|
}
|
|
14401
|
-
if (
|
|
14631
|
+
if (ts6.isElementAccessExpression(node) && hooks.size && (ts6.isIdentifier(node.expression) && node.expression.text === "ctx" || ts6.isPropertyAccessExpression(node.expression) && ts6.isIdentifier(node.expression.expression) && node.expression.expression.text === "ctx")) {
|
|
14402
14632
|
const line = source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1;
|
|
14403
|
-
report.ambiguities.push(`${
|
|
14633
|
+
report.ambiguities.push(`${relative5(report.package, file)}:${line}: computed ctx hook lookup prevents proving callback timing`);
|
|
14404
14634
|
}
|
|
14405
|
-
if (
|
|
14635
|
+
if (ts6.isPropertyAccessExpression(node) && ts6.isIdentifier(node.expression) && node.expression.text === "Engine" && ["call", "hook"].includes(node.name.text) && !(ts6.isCallExpression(node.parent) && node.parent.expression === node)) {
|
|
14406
14636
|
const line = source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1;
|
|
14407
|
-
report.ambiguities.push(`${
|
|
14637
|
+
report.ambiguities.push(`${relative5(report.package, file)}:${line}: indirect Engine.${node.name.text} lookup prevents proving timing/null behavior`);
|
|
14408
14638
|
}
|
|
14409
|
-
if (
|
|
14639
|
+
if (ts6.isCallExpression(node)) {
|
|
14410
14640
|
const expr = node.expression;
|
|
14411
14641
|
let kind;
|
|
14412
|
-
if (
|
|
14642
|
+
if (ts6.isPropertyAccessExpression(expr) && ts6.isIdentifier(expr.expression) && expr.expression.text === "Engine" && ["call", "hook"].includes(expr.name.text)) kind = expr.name.text;
|
|
14413
14643
|
if (kind) {
|
|
14414
14644
|
const arg = node.arguments[0];
|
|
14415
14645
|
const line = source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1;
|
|
14416
|
-
if (!arg || !
|
|
14646
|
+
if (!arg || !ts6.isStringLiteral(arg) && !ts6.isNoSubstitutionTemplateLiteral(arg)) report.ambiguities.push(`${relative5(report.package, file)}:${line}: dynamic Engine.${kind} reference prevents proving timing/null behavior`);
|
|
14417
14647
|
else {
|
|
14418
14648
|
const name = arg.text;
|
|
14419
|
-
if (!(kind === "call" ? calls.has(name) : hooks.has(name))) report.ambiguities.push(`${
|
|
14649
|
+
if (!(kind === "call" ? calls.has(name) : hooks.has(name))) report.ambiguities.push(`${relative5(report.package, file)}:${line}: Engine.${kind} references undeclared ${name}`);
|
|
14420
14650
|
else report.sourceReferences.push({ file, line, kind: `Engine.${kind}`, name, manualEdit: `review ${kind} lookup, null behavior and callback timing for ${name}` });
|
|
14421
14651
|
}
|
|
14422
14652
|
}
|
|
14423
|
-
if (
|
|
14653
|
+
if (ts6.isPropertyAccessExpression(expr) && ts6.isPropertyAccessExpression(expr.expression) && ts6.isIdentifier(expr.expression.expression) && expr.expression.expression.text === "ctx") {
|
|
14424
14654
|
const ns = expr.expression.name.text;
|
|
14425
14655
|
const name = expr.name.text;
|
|
14426
14656
|
if (hooks.get(name) === ns) report.sourceReferences.push({ file, line: source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1, kind: "ctx hook", name, manualEdit: `review callback timing and replace ctx.${ns}.${name} manually` });
|
|
14427
14657
|
}
|
|
14428
14658
|
}
|
|
14429
|
-
|
|
14659
|
+
ts6.forEachChild(node, visit);
|
|
14430
14660
|
};
|
|
14431
14661
|
visit(source);
|
|
14432
14662
|
}
|
|
14433
14663
|
}
|
|
14434
14664
|
function analyzeV1Migration(pluginDir, options = {}) {
|
|
14435
14665
|
const dir = resolve26(pluginDir);
|
|
14436
|
-
const destination =
|
|
14666
|
+
const destination = join36(dir, "gamedata", "functions.jsonc");
|
|
14437
14667
|
const report = { scope: SCOPE, package: dir, destination, entries: [], permissions: [], sourceReferences: [], generatedDeclarations: [], generatedDeclarationHashes: {}, recommendedEdits: [], ambiguities: [], filesChanged: [] };
|
|
14438
14668
|
if (pathExists(destination) && !options.force) report.ambiguities.push(`${destination}: destination already exists; use --force to replace it`);
|
|
14439
14669
|
let pkg;
|
|
14440
14670
|
try {
|
|
14441
|
-
pkg = parseFunctionFile(
|
|
14671
|
+
pkg = parseFunctionFile(join36(dir, "package.json"), readFileSync31(join36(dir, "package.json"), "utf8"));
|
|
14442
14672
|
} catch (e) {
|
|
14443
14673
|
report.ambiguities.push(`package.json: ${e.message}`);
|
|
14444
14674
|
return report;
|
|
@@ -14460,7 +14690,7 @@ function analyzeV1Migration(pluginDir, options = {}) {
|
|
|
14460
14690
|
}
|
|
14461
14691
|
let gd;
|
|
14462
14692
|
try {
|
|
14463
|
-
gd = parseFunctionFile(input,
|
|
14693
|
+
gd = parseFunctionFile(input, readFileSync31(input, "utf8"));
|
|
14464
14694
|
} catch (e) {
|
|
14465
14695
|
report.ambiguities.push(`gamedata: ${e.message}`);
|
|
14466
14696
|
return report;
|
|
@@ -14560,10 +14790,10 @@ function analyzeV1Migration(pluginDir, options = {}) {
|
|
|
14560
14790
|
}
|
|
14561
14791
|
}
|
|
14562
14792
|
report.output = author;
|
|
14563
|
-
report.generatedDeclarations = ["gamedata.d.ts", "hooks.d.ts"].map((n3) =>
|
|
14793
|
+
report.generatedDeclarations = ["gamedata.d.ts", "hooks.d.ts"].map((n3) => join36(dir, ".s2script", n3)).filter(existsSync21);
|
|
14564
14794
|
for (const file of report.generatedDeclarations) {
|
|
14565
14795
|
try {
|
|
14566
|
-
report.generatedDeclarationHashes[file] =
|
|
14796
|
+
report.generatedDeclarationHashes[file] = createHash6("sha256").update(readFileSync31(file)).digest("hex");
|
|
14567
14797
|
} catch (e) {
|
|
14568
14798
|
report.ambiguities.push(`${file}: generated declaration could not be read: ${e.message}`);
|
|
14569
14799
|
}
|
|
@@ -14582,7 +14812,7 @@ function migrateV1Package(pluginDir, options = {}) {
|
|
|
14582
14812
|
const report = analyzeV1Migration(pluginDir, options);
|
|
14583
14813
|
if (report.ambiguities.length || !report.output) return report;
|
|
14584
14814
|
const dest = report.destination;
|
|
14585
|
-
const temp =
|
|
14815
|
+
const temp = join36(dirname10(dest), `.functions.jsonc.${process.pid}.${randomUUID()}.tmp`);
|
|
14586
14816
|
try {
|
|
14587
14817
|
mkdirSync11(dirname10(dest), { recursive: true });
|
|
14588
14818
|
const fd2 = openSync(temp, "wx", 384);
|
|
@@ -14604,7 +14834,7 @@ function migrateV1Package(pluginDir, options = {}) {
|
|
|
14604
14834
|
report.publication = void 0;
|
|
14605
14835
|
report.ambiguities.push(`${dest}: publication failed: ${e.message}`);
|
|
14606
14836
|
} finally {
|
|
14607
|
-
if (
|
|
14837
|
+
if (existsSync21(temp)) unlinkSync(temp);
|
|
14608
14838
|
}
|
|
14609
14839
|
return report;
|
|
14610
14840
|
}
|
|
@@ -14623,9 +14853,9 @@ async function run11(argv2) {
|
|
|
14623
14853
|
}
|
|
14624
14854
|
|
|
14625
14855
|
// src/commands/pack.ts
|
|
14626
|
-
import { createHash as
|
|
14627
|
-
import { readFileSync as
|
|
14628
|
-
import { join as
|
|
14856
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
14857
|
+
import { readFileSync as readFileSync32, writeFileSync as writeFileSync24 } from "node:fs";
|
|
14858
|
+
import { join as join37, resolve as resolve27 } from "node:path";
|
|
14629
14859
|
function formatBytes(n3) {
|
|
14630
14860
|
if (n3 < 1e3) return `${n3}B`;
|
|
14631
14861
|
if (n3 < 1e3 * 1e3) return `${(n3 / 1e3).toFixed(1)}kB`;
|
|
@@ -14633,9 +14863,9 @@ function formatBytes(n3) {
|
|
|
14633
14863
|
}
|
|
14634
14864
|
function packPackage(dir) {
|
|
14635
14865
|
const absDir = resolve27(dir);
|
|
14636
|
-
const pkg = JSON.parse(
|
|
14866
|
+
const pkg = JSON.parse(readFileSync32(join37(absDir, "package.json"), "utf8"));
|
|
14637
14867
|
if (typeof pkg.name !== "string" || typeof pkg.version !== "string") {
|
|
14638
|
-
throw new Error(`${
|
|
14868
|
+
throw new Error(`${join37(absDir, "package.json")}: "name" and "version" are required to pack`);
|
|
14639
14869
|
}
|
|
14640
14870
|
const pack = packSourceTarball(absDir, pkg);
|
|
14641
14871
|
return {
|
|
@@ -14647,8 +14877,8 @@ function packPackage(dir) {
|
|
|
14647
14877
|
filename: tarballFilename(pkg.name, pkg.version),
|
|
14648
14878
|
size: pack.tarball.length,
|
|
14649
14879
|
unpackedSize: pack.unpackedSize,
|
|
14650
|
-
shasum:
|
|
14651
|
-
integrity: `sha512-${
|
|
14880
|
+
shasum: createHash7("sha1").update(pack.tarball).digest("hex"),
|
|
14881
|
+
integrity: `sha512-${createHash7("sha512").update(pack.tarball).digest("base64")}`,
|
|
14652
14882
|
files: pack.files,
|
|
14653
14883
|
entryCount: pack.files.length
|
|
14654
14884
|
}
|
|
@@ -14693,8 +14923,8 @@ async function run12(argv2) {
|
|
|
14693
14923
|
}
|
|
14694
14924
|
|
|
14695
14925
|
// src/commands/server.ts
|
|
14696
|
-
import { existsSync as
|
|
14697
|
-
import { join as
|
|
14926
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
14927
|
+
import { join as join38, resolve as resolve28 } from "node:path";
|
|
14698
14928
|
async function run13(argv2) {
|
|
14699
14929
|
const [sub, dir] = positionals(argv2, ["--registry", "--name"]);
|
|
14700
14930
|
if (sub !== "init") {
|
|
@@ -14703,7 +14933,7 @@ async function run13(argv2) {
|
|
|
14703
14933
|
}
|
|
14704
14934
|
const root = dir ? resolve28(dir) : findAddonRoot(".") ?? resolve28("addons", "s2script");
|
|
14705
14935
|
try {
|
|
14706
|
-
if (!
|
|
14936
|
+
if (!existsSync22(join38(root, "plugins"))) {
|
|
14707
14937
|
throw new Error(`${root} has no plugins/ directory \u2014 pass your addons/s2script directory`);
|
|
14708
14938
|
}
|
|
14709
14939
|
const report = await serverInit({
|
|
@@ -14715,7 +14945,7 @@ async function run13(argv2) {
|
|
|
14715
14945
|
for (const m of report.managed) console.log(`managed ${m.name}@${m.version} (${m.filename})`);
|
|
14716
14946
|
for (const u4 of report.unmanaged) console.log(`unmanaged ${u4.filename}: ${u4.reason}`);
|
|
14717
14947
|
console.log(
|
|
14718
|
-
`wrote ${
|
|
14948
|
+
`wrote ${join38(root, "plugins.json")} and plugins-lock.json \u2014 ${report.managed.length} managed, ${report.unmanaged.length} left as they are`
|
|
14719
14949
|
);
|
|
14720
14950
|
} catch (e) {
|
|
14721
14951
|
console.error(String(e instanceof Error ? e.message : e));
|