@neocompose/cli 0.1.3 → 0.1.4
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/neo.mjs +801 -131
- package/package.json +1 -1
package/dist/neo.mjs
CHANGED
|
@@ -1149,7 +1149,7 @@ var init_projection = __esm({
|
|
|
1149
1149
|
Custom: 7,
|
|
1150
1150
|
Enum: 8,
|
|
1151
1151
|
Lookup: 9,
|
|
1152
|
-
|
|
1152
|
+
NSProperty: 10,
|
|
1153
1153
|
Sprite: 11,
|
|
1154
1154
|
Audio: 12,
|
|
1155
1155
|
Function: 13,
|
|
@@ -1174,7 +1174,7 @@ var init_projection = __esm({
|
|
|
1174
1174
|
[ATTRIBUTE_TYPE.Enum]: "NeoEnum",
|
|
1175
1175
|
[ATTRIBUTE_TYPE.Lookup]: "NeoLookup",
|
|
1176
1176
|
[ATTRIBUTE_TYPE.DialogueLookup]: "NeoDialogueLookup",
|
|
1177
|
-
[ATTRIBUTE_TYPE.
|
|
1177
|
+
[ATTRIBUTE_TYPE.NSProperty]: "NeoProperty",
|
|
1178
1178
|
[ATTRIBUTE_TYPE.Sprite]: "NeoSprite",
|
|
1179
1179
|
[ATTRIBUTE_TYPE.Audio]: "NeoAudio",
|
|
1180
1180
|
[ATTRIBUTE_TYPE.Function]: "NeoFunction",
|
|
@@ -1197,7 +1197,8 @@ var init_projection = __esm({
|
|
|
1197
1197
|
"createdAt",
|
|
1198
1198
|
"updatedAt",
|
|
1199
1199
|
"valueId",
|
|
1200
|
-
"getter"
|
|
1200
|
+
"getter",
|
|
1201
|
+
"setter"
|
|
1201
1202
|
];
|
|
1202
1203
|
TYPE_VOLATILE_FIELDS = [
|
|
1203
1204
|
"projectId",
|
|
@@ -2180,17 +2181,19 @@ function reconstructProperty(file, property, context) {
|
|
|
2180
2181
|
data.multiselect = shape.head === "IReadOnlyList";
|
|
2181
2182
|
break;
|
|
2182
2183
|
}
|
|
2183
|
-
case ATTRIBUTE_TYPE.
|
|
2184
|
+
case ATTRIBUTE_TYPE.NSProperty: {
|
|
2184
2185
|
const code = namedString(marker, "Code", file);
|
|
2185
|
-
if (code === void 0) {
|
|
2186
|
+
if (code === void 0 && typeof data.extendsAttributeId !== "string") {
|
|
2186
2187
|
throw new SchemaParseError(
|
|
2187
|
-
"[
|
|
2188
|
+
"[NeoProperty] requires a Code argument.",
|
|
2188
2189
|
file,
|
|
2189
2190
|
marker.line,
|
|
2190
2191
|
marker.column
|
|
2191
2192
|
);
|
|
2192
2193
|
}
|
|
2193
|
-
data.code = code;
|
|
2194
|
+
if (code !== void 0) data.code = code;
|
|
2195
|
+
const setterCode = namedString(marker, "SetterCode", file);
|
|
2196
|
+
if (setterCode !== void 0) data.setterCode = setterCode;
|
|
2194
2197
|
const retJson = parseJsonArg(marker, "RetJson", file);
|
|
2195
2198
|
if (retJson !== void 0) data.returnTypeInfo = retJson;
|
|
2196
2199
|
break;
|
|
@@ -3631,11 +3634,12 @@ namespace NeoCompose.Schema
|
|
|
3631
3634
|
}
|
|
3632
3635
|
|
|
3633
3636
|
[AttributeUsage(AttributeTargets.Property)]
|
|
3634
|
-
public sealed class
|
|
3637
|
+
public sealed class NeoPropertyAttribute : NeoSchemaMemberAttribute
|
|
3635
3638
|
{
|
|
3636
3639
|
public string? Code { get; set; }
|
|
3640
|
+
public string? SetterCode { get; set; }
|
|
3637
3641
|
public string? RetJson { get; set; }
|
|
3638
|
-
public
|
|
3642
|
+
public NeoPropertyAttribute(string? id = null) : base(id) { }
|
|
3639
3643
|
}
|
|
3640
3644
|
|
|
3641
3645
|
[AttributeUsage(AttributeTargets.Property)]
|
|
@@ -3963,12 +3967,24 @@ function isGenericBindingsRecord(value) {
|
|
|
3963
3967
|
if (Array.isArray(value)) return false;
|
|
3964
3968
|
return Object.values(value).every(isGenericBinding);
|
|
3965
3969
|
}
|
|
3970
|
+
function dedupeSchemaKeyOrder(order) {
|
|
3971
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3972
|
+
const result = [];
|
|
3973
|
+
for (const schemaKey of order) {
|
|
3974
|
+
if (seen.has(schemaKey)) continue;
|
|
3975
|
+
seen.add(schemaKey);
|
|
3976
|
+
result.push(schemaKey);
|
|
3977
|
+
}
|
|
3978
|
+
return result;
|
|
3979
|
+
}
|
|
3966
3980
|
function getCustomTypeSchemaKeyOrder(type) {
|
|
3967
3981
|
const schemaKeys = Object.keys(type.schema);
|
|
3968
3982
|
if (type.schemaKeyOrder === void 0) return schemaKeys;
|
|
3969
|
-
const orderedKeys =
|
|
3983
|
+
const orderedKeys = dedupeSchemaKeyOrder(type.schemaKeyOrder);
|
|
3984
|
+
const seen = new Set(orderedKeys);
|
|
3970
3985
|
for (const schemaKey of schemaKeys) {
|
|
3971
|
-
if (
|
|
3986
|
+
if (seen.has(schemaKey)) continue;
|
|
3987
|
+
seen.add(schemaKey);
|
|
3972
3988
|
orderedKeys.push(schemaKey);
|
|
3973
3989
|
}
|
|
3974
3990
|
return orderedKeys;
|
|
@@ -4171,11 +4187,15 @@ function isAttributeDialogueLookupBase(value) {
|
|
|
4171
4187
|
if (typeof v.multiselect !== "boolean") return false;
|
|
4172
4188
|
return v.dialogueGroupId === null || typeof v.dialogueGroupId === "string";
|
|
4173
4189
|
}
|
|
4174
|
-
function
|
|
4175
|
-
const v = asTypedAttributeBase(value, 10 /*
|
|
4190
|
+
function isAttributeNSPropertyBase(value) {
|
|
4191
|
+
const v = asTypedAttributeBase(value, 10 /* NSProperty */);
|
|
4176
4192
|
if (v === null) return false;
|
|
4177
4193
|
if (typeof v.code !== "string") return false;
|
|
4178
4194
|
if (v.code.length === 0) return false;
|
|
4195
|
+
if (v.setterCode !== void 0 && typeof v.setterCode !== "string") {
|
|
4196
|
+
return false;
|
|
4197
|
+
}
|
|
4198
|
+
if (v.setterCode !== void 0 && v.setterCode.length === 0) return false;
|
|
4179
4199
|
return isNSTypeInfo(v.returnTypeInfo);
|
|
4180
4200
|
}
|
|
4181
4201
|
function isAttributeFunctionBase(value) {
|
|
@@ -4226,7 +4246,7 @@ var init_attribute_types = __esm({
|
|
|
4226
4246
|
AttributeType10[AttributeType10["Custom"] = 7] = "Custom";
|
|
4227
4247
|
AttributeType10[AttributeType10["Enum"] = 8] = "Enum";
|
|
4228
4248
|
AttributeType10[AttributeType10["Lookup"] = 9] = "Lookup";
|
|
4229
|
-
AttributeType10[AttributeType10["
|
|
4249
|
+
AttributeType10[AttributeType10["NSProperty"] = 10] = "NSProperty";
|
|
4230
4250
|
AttributeType10[AttributeType10["Sprite"] = 11] = "Sprite";
|
|
4231
4251
|
AttributeType10[AttributeType10["Audio"] = 12] = "Audio";
|
|
4232
4252
|
AttributeType10[AttributeType10["Function"] = 13] = "Function";
|
|
@@ -4487,7 +4507,7 @@ var init_generics = __esm({
|
|
|
4487
4507
|
0 /* Null */,
|
|
4488
4508
|
9 /* Lookup */,
|
|
4489
4509
|
18 /* DialogueLookup */,
|
|
4490
|
-
10 /*
|
|
4510
|
+
10 /* NSProperty */,
|
|
4491
4511
|
13 /* Function */,
|
|
4492
4512
|
21 /* Generic */
|
|
4493
4513
|
]);
|
|
@@ -6530,14 +6550,21 @@ function emitProperty(context, schemaKey, attributeRecord, memberNames, warnings
|
|
|
6530
6550
|
csType = multiselect ? "IReadOnlyList<NeoDialogueLookupRef>" : "NeoDialogueLookupRef";
|
|
6531
6551
|
break;
|
|
6532
6552
|
}
|
|
6533
|
-
case ATTRIBUTE_TYPE.
|
|
6534
|
-
|
|
6553
|
+
case ATTRIBUTE_TYPE.NSProperty: {
|
|
6554
|
+
const isOverride = typeof data.extendsAttributeId === "string";
|
|
6555
|
+
if (!isOverride && typeof data.code !== "string") {
|
|
6535
6556
|
throw new Error(
|
|
6536
|
-
`
|
|
6557
|
+
`NeoScript property "${attributeRecord.recordId}" is missing "code".`
|
|
6537
6558
|
);
|
|
6538
6559
|
}
|
|
6539
|
-
|
|
6540
|
-
|
|
6560
|
+
if (typeof data.code === "string") {
|
|
6561
|
+
delete remaining.code;
|
|
6562
|
+
args.push(`Code = ${csVerbatimString(data.code)}`);
|
|
6563
|
+
}
|
|
6564
|
+
if (typeof data.setterCode === "string") {
|
|
6565
|
+
delete remaining.setterCode;
|
|
6566
|
+
args.push(`SetterCode = ${csVerbatimString(data.setterCode)}`);
|
|
6567
|
+
}
|
|
6541
6568
|
if (data.returnTypeInfo !== void 0) {
|
|
6542
6569
|
delete remaining.returnTypeInfo;
|
|
6543
6570
|
args.push(
|
|
@@ -6885,9 +6912,10 @@ import {
|
|
|
6885
6912
|
} from "node:fs";
|
|
6886
6913
|
import { dirname as dirname2, join as join6 } from "node:path";
|
|
6887
6914
|
async function runPull(workspace, options) {
|
|
6915
|
+
const destructive = options.force || options.reset;
|
|
6888
6916
|
const hasBaseline = Object.keys(workspace.state.records).length > 0;
|
|
6889
6917
|
let localByKey = /* @__PURE__ */ new Map();
|
|
6890
|
-
if (hasBaseline && !
|
|
6918
|
+
if (hasBaseline && !destructive) {
|
|
6891
6919
|
const status = computeWorkspaceStatus(workspace);
|
|
6892
6920
|
if (status.conflictedFiles.length > 0) {
|
|
6893
6921
|
throw new Error(
|
|
@@ -6907,7 +6935,7 @@ ${status.parseErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
|
6907
6935
|
])
|
|
6908
6936
|
);
|
|
6909
6937
|
}
|
|
6910
|
-
if (!
|
|
6938
|
+
if (!destructive && workspace.state.headTransactionHash !== void 0) {
|
|
6911
6939
|
const convex = await createConvexClient(workspace);
|
|
6912
6940
|
const signal = await convex.query(api2.projectExportData.schemaSignal, {
|
|
6913
6941
|
projectId: workspace.config.projectId,
|
|
@@ -6933,7 +6961,7 @@ ${status.parseErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
|
6933
6961
|
if (serverRecord.deleted) continue;
|
|
6934
6962
|
const baseState = workspace.state.records[key];
|
|
6935
6963
|
const local = localByKey.get(key);
|
|
6936
|
-
if (
|
|
6964
|
+
if (destructive || baseState === void 0) {
|
|
6937
6965
|
plans.set(key, {
|
|
6938
6966
|
emitData: serverRecord.data,
|
|
6939
6967
|
serverHash: serverRecord.contentHash,
|
|
@@ -7338,7 +7366,7 @@ async function runInit(options) {
|
|
|
7338
7366
|
config,
|
|
7339
7367
|
state: readWorkspaceState(root)
|
|
7340
7368
|
};
|
|
7341
|
-
await runPull(workspace, { force: false });
|
|
7369
|
+
await runPull(workspace, { force: false, reset: false });
|
|
7342
7370
|
}
|
|
7343
7371
|
var init_init = __esm({
|
|
7344
7372
|
"src/commands/init.ts"() {
|
|
@@ -7508,11 +7536,17 @@ var init_compile_error = __esm({
|
|
|
7508
7536
|
CompileError = class extends Error {
|
|
7509
7537
|
line;
|
|
7510
7538
|
column;
|
|
7511
|
-
|
|
7539
|
+
unit;
|
|
7540
|
+
constructor(message, pos, unit) {
|
|
7512
7541
|
super(`${pos.line}:${pos.column}: ${message}`);
|
|
7513
7542
|
this.name = "CompileError";
|
|
7514
7543
|
this.line = pos.line;
|
|
7515
7544
|
this.column = pos.column;
|
|
7545
|
+
this.unit = unit;
|
|
7546
|
+
}
|
|
7547
|
+
withUnit(unit) {
|
|
7548
|
+
if (this.unit === void 0) this.unit = unit;
|
|
7549
|
+
return this;
|
|
7516
7550
|
}
|
|
7517
7551
|
};
|
|
7518
7552
|
}
|
|
@@ -9545,6 +9579,7 @@ var init_resolver = __esm({
|
|
|
9545
9579
|
init_project();
|
|
9546
9580
|
init_neoscript();
|
|
9547
9581
|
init_compile_error();
|
|
9582
|
+
init_core();
|
|
9548
9583
|
Scope = class {
|
|
9549
9584
|
constructor(parent) {
|
|
9550
9585
|
this.parent = parent;
|
|
@@ -9628,11 +9663,27 @@ var init_resolver = __esm({
|
|
|
9628
9663
|
}
|
|
9629
9664
|
}
|
|
9630
9665
|
} : null;
|
|
9666
|
+
if (ctx.mode === "setter" /* Setter */) {
|
|
9667
|
+
if (ctx.valueTypeInfo === void 0) {
|
|
9668
|
+
throw new Error("Resolver: Setter mode requires valueTypeInfo");
|
|
9669
|
+
}
|
|
9670
|
+
this.valueVariable = {
|
|
9671
|
+
id: "__value__",
|
|
9672
|
+
typeInfo: ctx.valueTypeInfo,
|
|
9673
|
+
pointer: {
|
|
9674
|
+
type: "value" /* value */,
|
|
9675
|
+
value: { typeInfo: ctx.valueTypeInfo, value: null }
|
|
9676
|
+
}
|
|
9677
|
+
};
|
|
9678
|
+
} else {
|
|
9679
|
+
this.valueVariable = null;
|
|
9680
|
+
}
|
|
9631
9681
|
}
|
|
9632
9682
|
ctx;
|
|
9633
9683
|
thisVariable;
|
|
9634
9684
|
rootVariable;
|
|
9635
9685
|
contextVariable;
|
|
9686
|
+
valueVariable;
|
|
9636
9687
|
/**
|
|
9637
9688
|
* Synthesized `Root` type. The resolver fabricates this from the project's
|
|
9638
9689
|
* root attribute ids so the body's `root.Assets` / `root.Save` /
|
|
@@ -9669,6 +9720,13 @@ var init_resolver = __esm({
|
|
|
9669
9720
|
variableId: this.contextVariable.id
|
|
9670
9721
|
});
|
|
9671
9722
|
}
|
|
9723
|
+
if (this.valueVariable) {
|
|
9724
|
+
scope.define({
|
|
9725
|
+
name: "value",
|
|
9726
|
+
type: this.valueVariable.typeInfo,
|
|
9727
|
+
variableId: this.valueVariable.id
|
|
9728
|
+
});
|
|
9729
|
+
}
|
|
9672
9730
|
if (this.ctx.migrationContext === true) {
|
|
9673
9731
|
scope.define({
|
|
9674
9732
|
name: "source",
|
|
@@ -9686,6 +9744,7 @@ var init_resolver = __esm({
|
|
|
9686
9744
|
const instructions = this.resolveStatements(body.body, scope);
|
|
9687
9745
|
const parameters = [this.thisVariable, this.rootVariable];
|
|
9688
9746
|
if (this.contextVariable) parameters.push(this.contextVariable);
|
|
9747
|
+
if (this.valueVariable) parameters.push(this.valueVariable);
|
|
9689
9748
|
return {
|
|
9690
9749
|
parameters,
|
|
9691
9750
|
instructions,
|
|
@@ -9728,6 +9787,12 @@ var init_resolver = __esm({
|
|
|
9728
9787
|
resolveStatement(stmt, scope) {
|
|
9729
9788
|
switch (stmt.kind) {
|
|
9730
9789
|
case "varDecl": {
|
|
9790
|
+
if (this.valueVariable && stmt.name === "value") {
|
|
9791
|
+
throw new CompileError(
|
|
9792
|
+
"Cannot declare a local named 'value' because it is the setter value parameter.",
|
|
9793
|
+
stmt.pos
|
|
9794
|
+
);
|
|
9795
|
+
}
|
|
9731
9796
|
const declared = this.resolveTypeAnnotation(stmt.type);
|
|
9732
9797
|
const initResolved = this.resolveExpr(stmt.init, scope, declared);
|
|
9733
9798
|
if (!isAssignable(initResolved.type, declared, this.ctx.types)) {
|
|
@@ -9804,7 +9869,7 @@ var init_resolver = __esm({
|
|
|
9804
9869
|
}
|
|
9805
9870
|
case "return": {
|
|
9806
9871
|
const expectedReturn = this.currentExpectedReturn();
|
|
9807
|
-
const inActionBody = this.ctx.mode
|
|
9872
|
+
const inActionBody = this.ctx.mode !== "getter" /* Getter */ && this.lambdaDepth === 0;
|
|
9808
9873
|
if (stmt.expr === null) {
|
|
9809
9874
|
if (inActionBody) {
|
|
9810
9875
|
return {
|
|
@@ -9827,7 +9892,7 @@ var init_resolver = __esm({
|
|
|
9827
9892
|
if (inActionBody) {
|
|
9828
9893
|
if (resolved.type.type !== 0 /* Null */) {
|
|
9829
9894
|
throw new CompileError(
|
|
9830
|
-
|
|
9895
|
+
`${this.ctx.mode === "setter" /* Setter */ ? "Setter" : "Action"} functions can only return null; got ${describeType(resolved.type)}`,
|
|
9831
9896
|
stmt.pos
|
|
9832
9897
|
);
|
|
9833
9898
|
}
|
|
@@ -9873,15 +9938,17 @@ var init_resolver = __esm({
|
|
|
9873
9938
|
);
|
|
9874
9939
|
if (!localAssignmentEntry && !this.ctx.allowMutation) {
|
|
9875
9940
|
throw new CompileError(
|
|
9876
|
-
"Only local variable assignment is allowed in getter contexts; save mutations require an action.",
|
|
9941
|
+
"Only local variable assignment is allowed in getter contexts; save mutations require an action or setter.",
|
|
9877
9942
|
stmt.pos
|
|
9878
9943
|
);
|
|
9879
9944
|
}
|
|
9880
|
-
const
|
|
9881
|
-
|
|
9882
|
-
|
|
9883
|
-
|
|
9884
|
-
|
|
9945
|
+
const propertyTarget = localAssignmentEntry ? null : this.resolveNSPropertyAssignmentTarget(
|
|
9946
|
+
stmt.target,
|
|
9947
|
+
scope,
|
|
9948
|
+
stmt.pos
|
|
9949
|
+
);
|
|
9950
|
+
const writability = localAssignmentEntry ? "local" /* Local */ : propertyTarget !== null ? "setter" /* Setter */ : this.validateWritableTarget(stmt.target, scope, stmt.pos);
|
|
9951
|
+
const readTarget = propertyTarget ?? this.resolveExpr(stmt.target, scope);
|
|
9885
9952
|
const target = localAssignmentEntry ? { pointer: readTarget.pointer, type: localAssignmentEntry.type } : readTarget;
|
|
9886
9953
|
let value;
|
|
9887
9954
|
if (stmt.op === "=") {
|
|
@@ -10668,7 +10735,7 @@ var init_resolver = __esm({
|
|
|
10668
10735
|
if (attr === null) return "inherit" /* Inherit */;
|
|
10669
10736
|
return this.getStorageResolver().declaredStorage(attr.id);
|
|
10670
10737
|
}
|
|
10671
|
-
|
|
10738
|
+
validateNSPropertyCollectionMutationTarget(expr, scope, pos) {
|
|
10672
10739
|
if (expr.kind !== "member") return;
|
|
10673
10740
|
const attr = this.resolveMemberAttribute(
|
|
10674
10741
|
expr.receiver,
|
|
@@ -10676,11 +10743,42 @@ var init_resolver = __esm({
|
|
|
10676
10743
|
scope,
|
|
10677
10744
|
pos
|
|
10678
10745
|
);
|
|
10679
|
-
if (attr?.type !== 10 /*
|
|
10746
|
+
if (attr?.type !== 10 /* NSProperty */) return;
|
|
10680
10747
|
throw new CompileError(
|
|
10681
|
-
`Cannot
|
|
10748
|
+
`Cannot call mutating methods on NeoScript property '${attr.name}'; assign a whole value via its setter instead.`,
|
|
10749
|
+
pos
|
|
10750
|
+
);
|
|
10751
|
+
}
|
|
10752
|
+
/** Resolve a whole-value assignment to a setter-backed NSProperty. */
|
|
10753
|
+
resolveNSPropertyAssignmentTarget(expr, scope, pos) {
|
|
10754
|
+
if (expr.kind !== "member") return null;
|
|
10755
|
+
const attr = this.resolveMemberAttribute(
|
|
10756
|
+
expr.receiver,
|
|
10757
|
+
expr.name,
|
|
10758
|
+
scope,
|
|
10682
10759
|
pos
|
|
10683
10760
|
);
|
|
10761
|
+
if (attr?.type !== 10 /* NSProperty */) return null;
|
|
10762
|
+
if (expr.optional === true) {
|
|
10763
|
+
throw new CompileError(
|
|
10764
|
+
`Cannot assign to NeoScript property '${attr.name}' through an optional receiver.`,
|
|
10765
|
+
pos
|
|
10766
|
+
);
|
|
10767
|
+
}
|
|
10768
|
+
const receiver = this.resolveExpr(expr.receiver, scope);
|
|
10769
|
+
if (!receiver.type.required) {
|
|
10770
|
+
throw new CompileError(
|
|
10771
|
+
`Cannot assign to NeoScript property '${attr.name}' through an optional receiver.`,
|
|
10772
|
+
pos
|
|
10773
|
+
);
|
|
10774
|
+
}
|
|
10775
|
+
if (!this.resolveNSPropertySetterSource(attr.id)) {
|
|
10776
|
+
throw new CompileError(
|
|
10777
|
+
`Cannot assign to NeoScript property '${attr.name}' because it does not declare a setter.`,
|
|
10778
|
+
pos
|
|
10779
|
+
);
|
|
10780
|
+
}
|
|
10781
|
+
return this.resolveExpr(expr, scope);
|
|
10684
10782
|
}
|
|
10685
10783
|
resolveMemberAttribute(receiverAst, name, scope, pos) {
|
|
10686
10784
|
const receiver = this.resolveExpr(receiverAst, scope);
|
|
@@ -11060,8 +11158,8 @@ var init_resolver = __esm({
|
|
|
11060
11158
|
pos
|
|
11061
11159
|
);
|
|
11062
11160
|
}
|
|
11063
|
-
if (attr.type === 10 /*
|
|
11064
|
-
const returnType = this.
|
|
11161
|
+
if (attr.type === 10 /* NSProperty */) {
|
|
11162
|
+
const returnType = this.resolveNSPropertyReturnType(attr.id);
|
|
11065
11163
|
if (!returnType) {
|
|
11066
11164
|
throw new CompileError(
|
|
11067
11165
|
`Getter '${attr.name}' has no \`returnTypeInfo\` (broken override chain?)`,
|
|
@@ -11646,10 +11744,14 @@ var init_resolver = __esm({
|
|
|
11646
11744
|
pos
|
|
11647
11745
|
);
|
|
11648
11746
|
}
|
|
11649
|
-
const writability = localMutation ? "local" /* Local */ : this.validateWritableTarget(callee.receiver, scope, pos);
|
|
11650
11747
|
if (!localMutation) {
|
|
11651
|
-
this.
|
|
11748
|
+
this.validateNSPropertyCollectionMutationTarget(
|
|
11749
|
+
callee.receiver,
|
|
11750
|
+
scope,
|
|
11751
|
+
pos
|
|
11752
|
+
);
|
|
11652
11753
|
}
|
|
11754
|
+
const writability = localMutation ? "local" /* Local */ : this.validateWritableTarget(callee.receiver, scope, pos);
|
|
11653
11755
|
const args = this.resolveCollectionMutationArgs(
|
|
11654
11756
|
callee,
|
|
11655
11757
|
expr.args,
|
|
@@ -11893,9 +11995,9 @@ var init_resolver = __esm({
|
|
|
11893
11995
|
pos
|
|
11894
11996
|
);
|
|
11895
11997
|
}
|
|
11896
|
-
if (signature.deferred && this.ctx.mode
|
|
11998
|
+
if (signature.deferred && this.ctx.mode === "getter" /* Getter */) {
|
|
11897
11999
|
throw new CompileError(
|
|
11898
|
-
`Deferred Function '${attr.name}' can only be called from
|
|
12000
|
+
`Deferred Function '${attr.name}' can only be called from action or setter code.`,
|
|
11899
12001
|
pos
|
|
11900
12002
|
);
|
|
11901
12003
|
}
|
|
@@ -12076,7 +12178,7 @@ var init_resolver = __esm({
|
|
|
12076
12178
|
}
|
|
12077
12179
|
/**
|
|
12078
12180
|
* Maps an attribute to the TNSTypeInfo the compiler exposes to user code.
|
|
12079
|
-
*
|
|
12181
|
+
* NSProperty attributes expose their `returnTypeInfo`. Lookup attributes
|
|
12080
12182
|
* resolve to the *referenced collection's entry type* so `lookup.field`
|
|
12081
12183
|
* autocompletes naturally.
|
|
12082
12184
|
*
|
|
@@ -12232,10 +12334,10 @@ var init_resolver = __esm({
|
|
|
12232
12334
|
}
|
|
12233
12335
|
return { type: 18 /* DialogueLookup */, required };
|
|
12234
12336
|
}
|
|
12235
|
-
case 10 /*
|
|
12236
|
-
if (!
|
|
12337
|
+
case 10 /* NSProperty */:
|
|
12338
|
+
if (!isAttributeNSPropertyBase(attr)) {
|
|
12237
12339
|
throw new CompileError(
|
|
12238
|
-
`
|
|
12340
|
+
`NSProperty attribute ${attr.id} failed isAttributeNSPropertyBase`,
|
|
12239
12341
|
{ line: 1, column: 1 }
|
|
12240
12342
|
);
|
|
12241
12343
|
}
|
|
@@ -12418,26 +12520,38 @@ var init_resolver = __esm({
|
|
|
12418
12520
|
return t;
|
|
12419
12521
|
}
|
|
12420
12522
|
/**
|
|
12421
|
-
* Walks an
|
|
12523
|
+
* Walks an NSProperty attribute's `extendsAttributeId` chain to find
|
|
12422
12524
|
* the first non-`undefined` `returnTypeInfo`.
|
|
12423
12525
|
*
|
|
12424
12526
|
* Override rows don't carry their own `returnTypeInfo` (per spec
|
|
12425
12527
|
* § 1.2) — they inherit from their parent. The walk terminates at
|
|
12426
12528
|
* the first row with `returnTypeInfo` set, the chain end (no
|
|
12427
|
-
* `extendsAttributeId`), or a non-
|
|
12529
|
+
* `extendsAttributeId`), or a non-NSProperty row (broken chain).
|
|
12428
12530
|
*/
|
|
12429
|
-
|
|
12531
|
+
resolveNSPropertyReturnType(attrId) {
|
|
12430
12532
|
const found = walkExtendsAttributeChain(
|
|
12431
12533
|
attrId,
|
|
12432
12534
|
this.ctx.attributes,
|
|
12433
|
-
// `requireType: AttributeType.
|
|
12535
|
+
// `requireType: AttributeType.NSProperty` only feeds NSProperty rows
|
|
12434
12536
|
// into this picker, but TS doesn't carry the filter through.
|
|
12435
|
-
// `
|
|
12537
|
+
// `isAttributeNSPropertyBase` narrows on the field set and returns
|
|
12436
12538
|
// a typed `returnTypeInfo` directly. Override rows that lack
|
|
12437
12539
|
// their own `returnTypeInfo` fail the guard, which is the
|
|
12438
12540
|
// correct "keep walking the chain" signal.
|
|
12439
|
-
(a) =>
|
|
12440
|
-
{ requireType: 10 /*
|
|
12541
|
+
(a) => isAttributeNSPropertyBase(a) ? a.returnTypeInfo : void 0,
|
|
12542
|
+
{ requireType: 10 /* NSProperty */ }
|
|
12543
|
+
);
|
|
12544
|
+
return found ?? null;
|
|
12545
|
+
}
|
|
12546
|
+
resolveNSPropertySetterSource(attrId) {
|
|
12547
|
+
const found = walkExtendsAttributeChain(
|
|
12548
|
+
attrId,
|
|
12549
|
+
this.ctx.attributes,
|
|
12550
|
+
(attribute) => {
|
|
12551
|
+
const setterCode = getField(attribute, "setterCode");
|
|
12552
|
+
return typeof setterCode === "string" ? setterCode : void 0;
|
|
12553
|
+
},
|
|
12554
|
+
{ requireType: 10 /* NSProperty */ }
|
|
12441
12555
|
);
|
|
12442
12556
|
return found ?? null;
|
|
12443
12557
|
}
|
|
@@ -12485,6 +12599,17 @@ function compileNSAction(code, ctx) {
|
|
|
12485
12599
|
});
|
|
12486
12600
|
return resolver.compileAction(ast);
|
|
12487
12601
|
}
|
|
12602
|
+
function compileNSSetter(code, ctx) {
|
|
12603
|
+
const ast = parseFunctionBody(code);
|
|
12604
|
+
const resolver = new Resolver({
|
|
12605
|
+
...ctx,
|
|
12606
|
+
returnTypeInfo: { type: 0 /* Null */, required: true },
|
|
12607
|
+
mode: "setter" /* Setter */,
|
|
12608
|
+
allowMutation: true,
|
|
12609
|
+
dialogueContext: null
|
|
12610
|
+
});
|
|
12611
|
+
return resolver.compileAction(ast);
|
|
12612
|
+
}
|
|
12488
12613
|
var init_compile = __esm({
|
|
12489
12614
|
"../src/database/neoscript/compile.ts"() {
|
|
12490
12615
|
"use strict";
|
|
@@ -12807,6 +12932,19 @@ function evaluateNSAction(action, ctx) {
|
|
|
12807
12932
|
}
|
|
12808
12933
|
return { writes };
|
|
12809
12934
|
}
|
|
12935
|
+
function evaluateNSSetter(setter, ctx, value, writes) {
|
|
12936
|
+
const scope = createTopLevelScope(ctx);
|
|
12937
|
+
scope.set("__value__", value);
|
|
12938
|
+
const result = evalInstructions(setter.instructions, scope, ctx, {
|
|
12939
|
+
allowFallthroughReturn: true,
|
|
12940
|
+
writes
|
|
12941
|
+
});
|
|
12942
|
+
if (result.kind === "return" && result.value !== null && result.value !== void 0) {
|
|
12943
|
+
throw new NSGetterRuntimeError(
|
|
12944
|
+
`Setter returned a non-null value: ${String(result.value)}`
|
|
12945
|
+
);
|
|
12946
|
+
}
|
|
12947
|
+
}
|
|
12810
12948
|
function createTopLevelScope(ctx) {
|
|
12811
12949
|
const scope = /* @__PURE__ */ new Map();
|
|
12812
12950
|
scope.set("__this__", ctx.thisValue);
|
|
@@ -12869,6 +13007,21 @@ function evalInstructions(instructions, scope, ctx, options) {
|
|
|
12869
13007
|
scope.set(ins.target.pointer.variableId, value);
|
|
12870
13008
|
break;
|
|
12871
13009
|
}
|
|
13010
|
+
if (ins.target.writability === "setter" /* Setter */) {
|
|
13011
|
+
if (!options.writes) {
|
|
13012
|
+
throw new NSGetterRuntimeError(
|
|
13013
|
+
"Setter calls cannot be evaluated in getter context."
|
|
13014
|
+
);
|
|
13015
|
+
}
|
|
13016
|
+
dispatchNSSetter(
|
|
13017
|
+
ins.target.pointer,
|
|
13018
|
+
value,
|
|
13019
|
+
scope,
|
|
13020
|
+
ctx,
|
|
13021
|
+
options.writes
|
|
13022
|
+
);
|
|
13023
|
+
break;
|
|
13024
|
+
}
|
|
12872
13025
|
validateAssignmentTarget(ins.target.pointer, scope, ctx);
|
|
12873
13026
|
if (!options.writes) {
|
|
12874
13027
|
throw new NSGetterRuntimeError(
|
|
@@ -12878,7 +13031,8 @@ function evalInstructions(instructions, scope, ctx, options) {
|
|
|
12878
13031
|
options.writes.push({
|
|
12879
13032
|
kind: "assign",
|
|
12880
13033
|
target: ins.target,
|
|
12881
|
-
value
|
|
13034
|
+
value,
|
|
13035
|
+
...resolvedDestinationFieldsForAssign(ins.target.pointer, scope, ctx)
|
|
12882
13036
|
});
|
|
12883
13037
|
break;
|
|
12884
13038
|
}
|
|
@@ -12908,6 +13062,90 @@ function validateAssignmentTarget(target, scope, ctx) {
|
|
|
12908
13062
|
throw new NSGetterRuntimeError(`List index out of bounds: ${index}`);
|
|
12909
13063
|
}
|
|
12910
13064
|
}
|
|
13065
|
+
function resolvedDestinationFieldsForAssign(target, scope, ctx) {
|
|
13066
|
+
if (target.type !== "keyOf" /* keyOf */) return {};
|
|
13067
|
+
const container = evalPointer(target.keyOf.pointer, scope, ctx);
|
|
13068
|
+
const containerValueId = findKnownRowIdByValueReference(container, ctx);
|
|
13069
|
+
if (containerValueId === null) return {};
|
|
13070
|
+
const key = evalPointer(target.keyOf.key, scope, ctx);
|
|
13071
|
+
if (typeof key !== "string" && typeof key !== "number") return {};
|
|
13072
|
+
return { resolvedDestination: { containerValueId, key } };
|
|
13073
|
+
}
|
|
13074
|
+
function resolvedDestinationFieldsForContainer(targetValue, ctx) {
|
|
13075
|
+
const containerValueId = findKnownRowIdByValueReference(targetValue, ctx);
|
|
13076
|
+
return containerValueId === null ? {} : { resolvedDestination: { containerValueId } };
|
|
13077
|
+
}
|
|
13078
|
+
function dispatchNSSetter(target, value, scope, ctx, writes) {
|
|
13079
|
+
if (target.type !== "callGetter" /* callGetter */) {
|
|
13080
|
+
throw new NSGetterRuntimeError(
|
|
13081
|
+
"Setter write target must be a callGetter pointer."
|
|
13082
|
+
);
|
|
13083
|
+
}
|
|
13084
|
+
const receiver = evalPointer(target.thisPointer, scope, ctx);
|
|
13085
|
+
if (receiver === null || receiver === void 0) {
|
|
13086
|
+
throw new NSGetterRuntimeError("Cannot invoke setter on a null receiver.");
|
|
13087
|
+
}
|
|
13088
|
+
const attributeId = resolveEffectiveNSPropertyAttributeId(
|
|
13089
|
+
target.attributeId,
|
|
13090
|
+
receiver,
|
|
13091
|
+
ctx
|
|
13092
|
+
);
|
|
13093
|
+
const stack = ctx.__setterCallStack ?? /* @__PURE__ */ new Set();
|
|
13094
|
+
if (stack.has(attributeId)) {
|
|
13095
|
+
const name = evalAttributeById(ctx.vm, attributeId)?.name ?? attributeId;
|
|
13096
|
+
throw new NSGetterRuntimeError(`Circular setter call: '${name}'.`);
|
|
13097
|
+
}
|
|
13098
|
+
const setter = resolveCompiledSetter(attributeId, ctx.vm.attributes);
|
|
13099
|
+
if (setter === null) {
|
|
13100
|
+
const name = evalAttributeById(ctx.vm, attributeId)?.name ?? attributeId;
|
|
13101
|
+
throw new NSGetterRuntimeError(
|
|
13102
|
+
`NeoScript property '${name}' has no compiled setter \u2014 save its code to compile it.`
|
|
13103
|
+
);
|
|
13104
|
+
}
|
|
13105
|
+
const innerStack = new Set(stack);
|
|
13106
|
+
innerStack.add(attributeId);
|
|
13107
|
+
evaluateNSSetter(
|
|
13108
|
+
setter,
|
|
13109
|
+
{
|
|
13110
|
+
...ctx,
|
|
13111
|
+
thisValue: receiver,
|
|
13112
|
+
__setterCallStack: innerStack
|
|
13113
|
+
},
|
|
13114
|
+
value,
|
|
13115
|
+
writes
|
|
13116
|
+
);
|
|
13117
|
+
}
|
|
13118
|
+
function resolveEffectiveNSPropertyAttributeId(staticAttributeId, receiver, ctx) {
|
|
13119
|
+
const placement = findSchemaPlacement(staticAttributeId, ctx.vm.types);
|
|
13120
|
+
if (placement === null) return staticAttributeId;
|
|
13121
|
+
const row = ctx.vm.values.find((candidate) => candidate.value === receiver);
|
|
13122
|
+
if (row === void 0) return staticAttributeId;
|
|
13123
|
+
const runtimeTypeId = customTypeIdForValueRow(row, ctx);
|
|
13124
|
+
if (runtimeTypeId === void 0) return staticAttributeId;
|
|
13125
|
+
let chain;
|
|
13126
|
+
try {
|
|
13127
|
+
chain = resolveInheritanceChain(runtimeTypeId, ctx.vm.types);
|
|
13128
|
+
} catch {
|
|
13129
|
+
return staticAttributeId;
|
|
13130
|
+
}
|
|
13131
|
+
const entry = mergeSchemas(chain).find(
|
|
13132
|
+
(candidate) => candidate.schemaKey === placement.schemaKey
|
|
13133
|
+
);
|
|
13134
|
+
if (entry?.attributeId === null || entry?.attributeId === void 0) {
|
|
13135
|
+
return staticAttributeId;
|
|
13136
|
+
}
|
|
13137
|
+
const effective = evalAttributeById(ctx.vm, entry.attributeId);
|
|
13138
|
+
return effective?.type === 10 /* NSProperty */ ? entry.attributeId : staticAttributeId;
|
|
13139
|
+
}
|
|
13140
|
+
function resolveCompiledSetter(attributeId, attributes) {
|
|
13141
|
+
const found = walkExtendsAttributeChain(
|
|
13142
|
+
attributeId,
|
|
13143
|
+
attributes,
|
|
13144
|
+
(attribute) => attribute.setter,
|
|
13145
|
+
{ requireType: 10 /* NSProperty */ }
|
|
13146
|
+
);
|
|
13147
|
+
return found ?? null;
|
|
13148
|
+
}
|
|
12911
13149
|
function evalCollectionMutationInstruction(ins, scope, ctx, options) {
|
|
12912
13150
|
const targetValue = evalPointer(ins.target.pointer, scope, ctx);
|
|
12913
13151
|
const args = ins.args.map((arg) => evalPointer(arg, scope, ctx));
|
|
@@ -12929,7 +13167,8 @@ function evalCollectionMutationInstruction(ins, scope, ctx, options) {
|
|
|
12929
13167
|
options.writes.push({
|
|
12930
13168
|
kind: "add",
|
|
12931
13169
|
target: ins.target,
|
|
12932
|
-
value: isLookupSet ? lookupSetSelectionValue(args[0], ctx) : args[0]
|
|
13170
|
+
value: isLookupSet ? lookupSetSelectionValue(args[0], ctx) : args[0],
|
|
13171
|
+
...resolvedDestinationFieldsForContainer(targetValue, ctx)
|
|
12933
13172
|
});
|
|
12934
13173
|
return;
|
|
12935
13174
|
}
|
|
@@ -12937,7 +13176,8 @@ function evalCollectionMutationInstruction(ins, scope, ctx, options) {
|
|
|
12937
13176
|
kind: "add",
|
|
12938
13177
|
target: ins.target,
|
|
12939
13178
|
key: String(args[0]),
|
|
12940
|
-
value: args[1]
|
|
13179
|
+
value: args[1],
|
|
13180
|
+
...resolvedDestinationFieldsForContainer(targetValue, ctx)
|
|
12941
13181
|
});
|
|
12942
13182
|
return;
|
|
12943
13183
|
case "Remove" /* Remove */:
|
|
@@ -12945,27 +13185,31 @@ function evalCollectionMutationInstruction(ins, scope, ctx, options) {
|
|
|
12945
13185
|
options.writes.push({
|
|
12946
13186
|
kind: "remove",
|
|
12947
13187
|
target: ins.target,
|
|
12948
|
-
value: isLookupSet ? lookupSetSelectionValue(args[0], ctx) : args[0]
|
|
13188
|
+
value: isLookupSet ? lookupSetSelectionValue(args[0], ctx) : args[0],
|
|
13189
|
+
...resolvedDestinationFieldsForContainer(targetValue, ctx)
|
|
12949
13190
|
});
|
|
12950
13191
|
return;
|
|
12951
13192
|
}
|
|
12952
13193
|
options.writes.push({
|
|
12953
13194
|
kind: "remove",
|
|
12954
13195
|
target: ins.target,
|
|
12955
|
-
key: String(args[0])
|
|
13196
|
+
key: String(args[0]),
|
|
13197
|
+
...resolvedDestinationFieldsForContainer(targetValue, ctx)
|
|
12956
13198
|
});
|
|
12957
13199
|
return;
|
|
12958
13200
|
case "RemoveAt" /* RemoveAt */:
|
|
12959
13201
|
options.writes.push({
|
|
12960
13202
|
kind: "remove",
|
|
12961
13203
|
target: ins.target,
|
|
12962
|
-
index: numberArg(args[0], "RemoveAt index")
|
|
13204
|
+
index: numberArg(args[0], "RemoveAt index"),
|
|
13205
|
+
...resolvedDestinationFieldsForContainer(targetValue, ctx)
|
|
12963
13206
|
});
|
|
12964
13207
|
return;
|
|
12965
13208
|
case "Clear" /* Clear */:
|
|
12966
13209
|
options.writes.push({
|
|
12967
13210
|
kind: "clear",
|
|
12968
|
-
target: ins.target
|
|
13211
|
+
target: ins.target,
|
|
13212
|
+
...resolvedDestinationFieldsForContainer(targetValue, ctx)
|
|
12969
13213
|
});
|
|
12970
13214
|
return;
|
|
12971
13215
|
}
|
|
@@ -13290,9 +13534,8 @@ function dispatchNSGetterById(attributeId, receiver, ctx) {
|
|
|
13290
13534
|
const innerStack = new Set(stack);
|
|
13291
13535
|
innerStack.add(attributeId);
|
|
13292
13536
|
return evaluateNSGetter(getter, {
|
|
13293
|
-
|
|
13537
|
+
...ctx,
|
|
13294
13538
|
thisValue: receiver,
|
|
13295
|
-
rootValue: ctx.rootValue,
|
|
13296
13539
|
__getterCallStack: innerStack
|
|
13297
13540
|
});
|
|
13298
13541
|
}
|
|
@@ -13301,7 +13544,7 @@ function resolveCompiledGetter(attrId, attributes) {
|
|
|
13301
13544
|
attrId,
|
|
13302
13545
|
attributes,
|
|
13303
13546
|
(a) => a.getter,
|
|
13304
|
-
{ requireType: 10 /*
|
|
13547
|
+
{ requireType: 10 /* NSProperty */ }
|
|
13305
13548
|
);
|
|
13306
13549
|
return found ?? null;
|
|
13307
13550
|
}
|
|
@@ -13441,7 +13684,7 @@ function dispatchSchemaMember(receiver, schemaKey, ctx) {
|
|
|
13441
13684
|
if (entry.attributeId === null) return { kind: "no-info" };
|
|
13442
13685
|
const attr = evalAttributeById(ctx.vm, entry.attributeId);
|
|
13443
13686
|
if (!attr) return { kind: "no-info" };
|
|
13444
|
-
if (attr.type === 10 /*
|
|
13687
|
+
if (attr.type === 10 /* NSProperty */) {
|
|
13445
13688
|
if (!resolveCompiledGetter(entry.attributeId, ctx.vm.attributes)) {
|
|
13446
13689
|
return { kind: "no-info" };
|
|
13447
13690
|
}
|
|
@@ -14338,6 +14581,71 @@ function resolveThisType(thisRef, document) {
|
|
|
14338
14581
|
`--this "${thisRef}" is not a known type name, type id, or value id.`
|
|
14339
14582
|
);
|
|
14340
14583
|
}
|
|
14584
|
+
function resolveNSPropertyScriptTarget(attributeRef, document) {
|
|
14585
|
+
if (attributeRef === null) {
|
|
14586
|
+
throw new Error(
|
|
14587
|
+
"Setter mode requires --attribute <id-or-name> so `this` and `value` can be typed."
|
|
14588
|
+
);
|
|
14589
|
+
}
|
|
14590
|
+
const matches = document.attributes.filter(
|
|
14591
|
+
(attribute) => attribute.type === 10 && (attribute.id === attributeRef || attribute.name === attributeRef)
|
|
14592
|
+
);
|
|
14593
|
+
if (matches.length === 0) {
|
|
14594
|
+
throw new Error(
|
|
14595
|
+
`--attribute "${attributeRef}" is not a known NeoScript property id or name.`
|
|
14596
|
+
);
|
|
14597
|
+
}
|
|
14598
|
+
if (matches.length > 1) {
|
|
14599
|
+
throw new Error(
|
|
14600
|
+
`--attribute "${attributeRef}" matches multiple NeoScript properties; pass the stable attribute id.`
|
|
14601
|
+
);
|
|
14602
|
+
}
|
|
14603
|
+
return matches[0];
|
|
14604
|
+
}
|
|
14605
|
+
function resolveAttributeContainingType(attribute, document) {
|
|
14606
|
+
const attributeId = attribute.id;
|
|
14607
|
+
if (typeof attributeId !== "string") {
|
|
14608
|
+
throw new Error(
|
|
14609
|
+
"Setter mode selected a NeoScript property without a stable id."
|
|
14610
|
+
);
|
|
14611
|
+
}
|
|
14612
|
+
const matches = document.types.filter((type) => {
|
|
14613
|
+
const schema = type.schema;
|
|
14614
|
+
return isObjectRecord2(schema) && Object.values(schema).includes(attributeId);
|
|
14615
|
+
});
|
|
14616
|
+
if (matches.length === 0) {
|
|
14617
|
+
throw new Error(
|
|
14618
|
+
`NeoScript property "${String(attribute.name ?? attributeId)}" is not placed on a custom type.`
|
|
14619
|
+
);
|
|
14620
|
+
}
|
|
14621
|
+
if (matches.length > 1) {
|
|
14622
|
+
throw new Error(
|
|
14623
|
+
`NeoScript property "${String(attribute.name ?? attributeId)}" is placed on multiple custom types; pass a stable override attribute id that identifies one placement.`
|
|
14624
|
+
);
|
|
14625
|
+
}
|
|
14626
|
+
return matches[0];
|
|
14627
|
+
}
|
|
14628
|
+
function resolveScriptPropertyReturnTypeInfo(attribute, attributes) {
|
|
14629
|
+
let current = attribute;
|
|
14630
|
+
const visited = /* @__PURE__ */ new Set();
|
|
14631
|
+
while (current !== void 0) {
|
|
14632
|
+
if (current.returnTypeInfo !== void 0) {
|
|
14633
|
+
return current.returnTypeInfo;
|
|
14634
|
+
}
|
|
14635
|
+
const parentId = current.extendsAttributeId;
|
|
14636
|
+
if (typeof parentId !== "string") break;
|
|
14637
|
+
if (visited.has(parentId)) {
|
|
14638
|
+
throw new Error(
|
|
14639
|
+
`Cannot resolve NeoScript property return type: circular attribute chain at "${parentId}".`
|
|
14640
|
+
);
|
|
14641
|
+
}
|
|
14642
|
+
visited.add(parentId);
|
|
14643
|
+
current = attributes.find((candidate) => candidate.id === parentId);
|
|
14644
|
+
}
|
|
14645
|
+
throw new Error(
|
|
14646
|
+
`NeoScript property "${String(attribute.name ?? attribute.id)}" has no returnTypeInfo in its base chain.`
|
|
14647
|
+
);
|
|
14648
|
+
}
|
|
14341
14649
|
function resolveThisValue(thisRef, document) {
|
|
14342
14650
|
if (thisRef === null) return null;
|
|
14343
14651
|
const value = document.values.find((entry) => entry.id === thisRef);
|
|
@@ -14379,7 +14687,18 @@ async function runScript(workspace, command, options) {
|
|
|
14379
14687
|
return;
|
|
14380
14688
|
}
|
|
14381
14689
|
const source = readSource(options);
|
|
14382
|
-
|
|
14690
|
+
if (options.mode === "setter" && command !== "check" && command !== "compile") {
|
|
14691
|
+
throw new Error(
|
|
14692
|
+
"Setter mode supports only `neo script check` and `neo script compile` in v1; eval/apply require a concrete receiver and transactional write semantics."
|
|
14693
|
+
);
|
|
14694
|
+
}
|
|
14695
|
+
const setterAttribute = options.mode === "setter" ? resolveNSPropertyScriptTarget(options.attributeRef, document) : null;
|
|
14696
|
+
if (setterAttribute !== null && options.returns !== null) {
|
|
14697
|
+
throw new Error(
|
|
14698
|
+
"Setter mode derives the value type from --attribute; do not pass --returns."
|
|
14699
|
+
);
|
|
14700
|
+
}
|
|
14701
|
+
const thisType = setterAttribute === null ? resolveThisType(options.thisRef, document) : resolveAttributeContainingType(setterAttribute, document);
|
|
14383
14702
|
const compileContext = {
|
|
14384
14703
|
project: document.project,
|
|
14385
14704
|
attributes: document.attributes,
|
|
@@ -14391,14 +14710,32 @@ async function runScript(workspace, command, options) {
|
|
|
14391
14710
|
};
|
|
14392
14711
|
let compiled;
|
|
14393
14712
|
try {
|
|
14394
|
-
|
|
14713
|
+
if (options.mode === "setter") {
|
|
14714
|
+
if (setterAttribute === null) {
|
|
14715
|
+
throw new Error("Setter mode requires an NSProperty attribute target.");
|
|
14716
|
+
}
|
|
14717
|
+
compiled = compileNSSetter(source, {
|
|
14718
|
+
project: document.project,
|
|
14719
|
+
attributes: document.attributes,
|
|
14720
|
+
types: document.types,
|
|
14721
|
+
enums: document.enums,
|
|
14722
|
+
thisType,
|
|
14723
|
+
valueTypeInfo: resolveScriptPropertyReturnTypeInfo(
|
|
14724
|
+
setterAttribute,
|
|
14725
|
+
document.attributes
|
|
14726
|
+
)
|
|
14727
|
+
});
|
|
14728
|
+
} else {
|
|
14729
|
+
compiled = command === "apply" || options.mode === "action" ? compileNSAction(source, compileContext) : compileNSGetter(source, compileContext);
|
|
14730
|
+
}
|
|
14395
14731
|
} catch (error) {
|
|
14396
14732
|
if (error instanceof CompileError) {
|
|
14397
14733
|
const report2 = {
|
|
14398
14734
|
ok: false,
|
|
14399
14735
|
error: error.message,
|
|
14400
14736
|
line: error.line,
|
|
14401
|
-
column: error.column
|
|
14737
|
+
column: error.column,
|
|
14738
|
+
unit: options.mode === "setter" ? "setter" : void 0
|
|
14402
14739
|
};
|
|
14403
14740
|
const hint = options.returns === null && error.message.includes("not assignable to declared return type") ? '\n(eval defaults to an unknown return type \u2014 pass --returns, e.g. --returns "string[]")' : "";
|
|
14404
14741
|
console.log(
|
|
@@ -14556,40 +14893,86 @@ function runCheckAll(document, options) {
|
|
|
14556
14893
|
const results = [];
|
|
14557
14894
|
for (const attribute of document.attributes) {
|
|
14558
14895
|
if (attribute.type !== 10) continue;
|
|
14559
|
-
if (typeof attribute.code !== "string")
|
|
14560
|
-
|
|
14896
|
+
if (typeof attribute.code !== "string" && typeof attribute.setterCode !== "string") {
|
|
14897
|
+
continue;
|
|
14898
|
+
}
|
|
14561
14899
|
const thisType = typeByAttributeId.get(String(attribute.id)) ?? null;
|
|
14562
|
-
|
|
14563
|
-
|
|
14564
|
-
|
|
14565
|
-
|
|
14566
|
-
|
|
14567
|
-
|
|
14568
|
-
|
|
14569
|
-
|
|
14570
|
-
|
|
14900
|
+
const context = {
|
|
14901
|
+
project: document.project,
|
|
14902
|
+
attributes: document.attributes,
|
|
14903
|
+
types: document.types,
|
|
14904
|
+
enums: document.enums,
|
|
14905
|
+
thisType,
|
|
14906
|
+
returnTypeInfo: resolveScriptPropertyReturnTypeInfo(
|
|
14907
|
+
attribute,
|
|
14908
|
+
document.attributes
|
|
14909
|
+
),
|
|
14910
|
+
dialogueContext: null
|
|
14911
|
+
};
|
|
14912
|
+
const checks = [];
|
|
14913
|
+
if (typeof attribute.code === "string") {
|
|
14914
|
+
checks.push({
|
|
14915
|
+
unit: "getter",
|
|
14916
|
+
run: () => {
|
|
14917
|
+
compileNSGetter(attribute.code, context);
|
|
14918
|
+
}
|
|
14571
14919
|
});
|
|
14572
|
-
|
|
14573
|
-
|
|
14574
|
-
|
|
14575
|
-
|
|
14576
|
-
|
|
14577
|
-
|
|
14578
|
-
|
|
14579
|
-
|
|
14580
|
-
|
|
14920
|
+
}
|
|
14921
|
+
if (typeof attribute.setterCode === "string") {
|
|
14922
|
+
checks.push({
|
|
14923
|
+
unit: "setter",
|
|
14924
|
+
run: () => {
|
|
14925
|
+
compileNSSetter(
|
|
14926
|
+
attribute.setterCode,
|
|
14927
|
+
{
|
|
14928
|
+
project: document.project,
|
|
14929
|
+
attributes: document.attributes,
|
|
14930
|
+
types: document.types,
|
|
14931
|
+
enums: document.enums,
|
|
14932
|
+
thisType,
|
|
14933
|
+
valueTypeInfo: resolveScriptPropertyReturnTypeInfo(
|
|
14934
|
+
attribute,
|
|
14935
|
+
document.attributes
|
|
14936
|
+
)
|
|
14937
|
+
}
|
|
14938
|
+
);
|
|
14939
|
+
}
|
|
14581
14940
|
});
|
|
14582
|
-
|
|
14583
|
-
|
|
14584
|
-
|
|
14585
|
-
|
|
14941
|
+
}
|
|
14942
|
+
for (const check of checks) {
|
|
14943
|
+
checked += 1;
|
|
14944
|
+
try {
|
|
14945
|
+
check.run();
|
|
14946
|
+
results.push({
|
|
14947
|
+
id: attribute.id,
|
|
14948
|
+
name: attribute.name,
|
|
14949
|
+
unit: check.unit,
|
|
14950
|
+
ok: true
|
|
14951
|
+
});
|
|
14952
|
+
} catch (error) {
|
|
14953
|
+
failures += 1;
|
|
14954
|
+
const message = error instanceof CompileError ? `${error.line}:${error.column} ${error.message}` : error instanceof Error ? error.message : String(error);
|
|
14955
|
+
results.push({
|
|
14956
|
+
id: attribute.id,
|
|
14957
|
+
name: attribute.name,
|
|
14958
|
+
unit: check.unit,
|
|
14959
|
+
ok: false,
|
|
14960
|
+
error: message
|
|
14961
|
+
});
|
|
14962
|
+
if (!options.json) {
|
|
14963
|
+
console.log(
|
|
14964
|
+
`FAIL ${String(attribute.name)} (${String(attribute.id)}) [${check.unit}]: ${message}`
|
|
14965
|
+
);
|
|
14966
|
+
}
|
|
14586
14967
|
}
|
|
14587
14968
|
}
|
|
14588
14969
|
}
|
|
14589
14970
|
if (options.json) {
|
|
14590
14971
|
console.log(JSON.stringify({ checked, failures, results }, null, 2));
|
|
14591
14972
|
} else {
|
|
14592
|
-
console.log(
|
|
14973
|
+
console.log(
|
|
14974
|
+
`${checked} property body/bodies checked, ${failures} failure(s).`
|
|
14975
|
+
);
|
|
14593
14976
|
}
|
|
14594
14977
|
if (failures > 0) process.exitCode = 1;
|
|
14595
14978
|
}
|
|
@@ -14837,6 +15220,17 @@ function resolveWriteTarget(write, env, migrationName) {
|
|
|
14837
15220
|
`Migration "${migrationName}" produced a "${write.kind}" collection mutation; the runner applies scalar assignments only (creating/deleting value records is not yet supported).`
|
|
14838
15221
|
);
|
|
14839
15222
|
}
|
|
15223
|
+
const resolved = write.resolvedDestination;
|
|
15224
|
+
if (resolved !== void 0 && resolved.key !== void 0) {
|
|
15225
|
+
const container2 = env.valueById.get(resolved.containerValueId)?.value;
|
|
15226
|
+
const leaf2 = Array.isArray(container2) && typeof resolved.key === "number" ? container2[resolved.key] : isObjectRecord2(container2) ? container2[String(resolved.key)] : void 0;
|
|
15227
|
+
if (typeof leaf2 !== "string") {
|
|
15228
|
+
throw new Error(
|
|
15229
|
+
`Migration "${migrationName}" resolved its assignment to container "${resolved.containerValueId}", but key "${String(resolved.key)}" has no stored value id.`
|
|
15230
|
+
);
|
|
15231
|
+
}
|
|
15232
|
+
return { leafValueId: leaf2 };
|
|
15233
|
+
}
|
|
14840
15234
|
const target = write.target;
|
|
14841
15235
|
if (!isObjectRecord2(target) || !isObjectRecord2(target.pointer)) {
|
|
14842
15236
|
throw new Error(
|
|
@@ -14920,6 +15314,11 @@ function resolveContainerMap(pointer, env, migrationName) {
|
|
|
14920
15314
|
);
|
|
14921
15315
|
}
|
|
14922
15316
|
function resolveCollectionTarget(write, env, migrationName) {
|
|
15317
|
+
if (write.resolvedDestination !== void 0) {
|
|
15318
|
+
return {
|
|
15319
|
+
containerValueId: write.resolvedDestination.containerValueId
|
|
15320
|
+
};
|
|
15321
|
+
}
|
|
14923
15322
|
const target = isObjectRecord2(write.target) ? write.target : {};
|
|
14924
15323
|
const pointer = isObjectRecord2(target.pointer) ? target.pointer : {};
|
|
14925
15324
|
if (pointer.type === "keyOf" && isObjectRecord2(pointer.keyOf)) {
|
|
@@ -15526,7 +15925,7 @@ async function runBranch(workspace, subcommand, positional, fromRef) {
|
|
|
15526
15925
|
success(
|
|
15527
15926
|
`Switched to ${color.bold(displayLabel(target))} ${color.dim(`(${target.id})`)}. Pulling\u2026`
|
|
15528
15927
|
);
|
|
15529
|
-
await runPull(workspace, { force: true });
|
|
15928
|
+
await runPull(workspace, { force: true, reset: false });
|
|
15530
15929
|
return;
|
|
15531
15930
|
}
|
|
15532
15931
|
if (subcommand === "delete") {
|
|
@@ -15758,7 +16157,7 @@ async function runMerge(workspace, sourceRef, dryRun, runMigrations = false) {
|
|
|
15758
16157
|
}
|
|
15759
16158
|
if (merged > 0) {
|
|
15760
16159
|
console.log("Pulling merged state...");
|
|
15761
|
-
await runPull(workspace, { force: false });
|
|
16160
|
+
await runPull(workspace, { force: false, reset: false });
|
|
15762
16161
|
}
|
|
15763
16162
|
if (runMigrations) {
|
|
15764
16163
|
const { runMigrate: runMigrate2 } = await Promise.resolve().then(() => (init_migrate(), migrate_exports));
|
|
@@ -16640,7 +17039,13 @@ function checkWriteOwnership(write, compiledAction, label, ctx, world, violate)
|
|
|
16640
17039
|
);
|
|
16641
17040
|
return;
|
|
16642
17041
|
}
|
|
16643
|
-
const rowId = resolveWriteRowId(
|
|
17042
|
+
const rowId = resolveWriteRowId(
|
|
17043
|
+
write,
|
|
17044
|
+
target,
|
|
17045
|
+
compiledAction,
|
|
17046
|
+
ctx,
|
|
17047
|
+
world
|
|
17048
|
+
);
|
|
16644
17049
|
if (rowId === null) {
|
|
16645
17050
|
violate(
|
|
16646
17051
|
label,
|
|
@@ -16690,7 +17095,15 @@ function targetLiteralKey(target) {
|
|
|
16690
17095
|
if (!isObjectRecord2(key) || !isObjectRecord2(key.value)) return null;
|
|
16691
17096
|
return typeof key.value.value === "string" ? key.value.value : null;
|
|
16692
17097
|
}
|
|
16693
|
-
function resolveWriteRowId(target, compiledAction, ctx, world) {
|
|
17098
|
+
function resolveWriteRowId(write, target, compiledAction, ctx, world) {
|
|
17099
|
+
const resolved = write.resolvedDestination;
|
|
17100
|
+
if (resolved !== void 0) {
|
|
17101
|
+
if (write.kind !== "assign") return resolved.containerValueId;
|
|
17102
|
+
if (resolved.key === void 0) return null;
|
|
17103
|
+
const container = world.valueById.get(resolved.containerValueId)?.value;
|
|
17104
|
+
const leaf = Array.isArray(container) && typeof resolved.key === "number" ? container[resolved.key] : isObjectRecord2(container) ? container[String(resolved.key)] : void 0;
|
|
17105
|
+
return typeof leaf === "string" && world.valueById.has(leaf) ? leaf : null;
|
|
17106
|
+
}
|
|
16694
17107
|
const pointer = isObjectRecord2(target.pointer) ? target.pointer : target;
|
|
16695
17108
|
const evalPointer2 = (p) => {
|
|
16696
17109
|
const getter = {
|
|
@@ -17898,6 +18311,7 @@ var init_export = __esm({
|
|
|
17898
18311
|
// src/commands/push.ts
|
|
17899
18312
|
var push_exports = {};
|
|
17900
18313
|
__export(push_exports, {
|
|
18314
|
+
prepareNSPropertySetterChanges: () => prepareNSPropertySetterChanges,
|
|
17901
18315
|
rewriteFilesFromState: () => rewriteFilesFromState,
|
|
17902
18316
|
runPush: () => runPush
|
|
17903
18317
|
});
|
|
@@ -17962,6 +18376,7 @@ ${status.parseErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
|
17962
18376
|
console.log("Nothing to push \u2014 working copy is clean.");
|
|
17963
18377
|
return;
|
|
17964
18378
|
}
|
|
18379
|
+
prepareNSPropertySetterChanges(workspace, status);
|
|
17965
18380
|
assignPendingIds(status.changes);
|
|
17966
18381
|
const now = Date.now();
|
|
17967
18382
|
for (const change of status.changes) {
|
|
@@ -17972,15 +18387,12 @@ ${status.parseErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
|
17972
18387
|
action: compileMigrationAction(status, change.nextData)
|
|
17973
18388
|
};
|
|
17974
18389
|
}
|
|
17975
|
-
if (change.recordKind === "attribute" && change.nextData.type === 10
|
|
17976
|
-
change.nextData =
|
|
17977
|
-
|
|
17978
|
-
|
|
17979
|
-
|
|
17980
|
-
|
|
17981
|
-
change.nextData
|
|
17982
|
-
)
|
|
17983
|
-
};
|
|
18390
|
+
if (change.recordKind === "attribute" && change.nextData.type === 10) {
|
|
18391
|
+
change.nextData = await compileNSPropertyChange(
|
|
18392
|
+
workspace,
|
|
18393
|
+
status,
|
|
18394
|
+
change.nextData
|
|
18395
|
+
);
|
|
17984
18396
|
}
|
|
17985
18397
|
if (change.kind === "create") {
|
|
17986
18398
|
change.nextData = {
|
|
@@ -18191,7 +18603,7 @@ function rewriteFilesFromState(workspace) {
|
|
|
18191
18603
|
workspace.state.records[key] = nextState;
|
|
18192
18604
|
}
|
|
18193
18605
|
}
|
|
18194
|
-
async function
|
|
18606
|
+
async function compileNSPropertyChange(workspace, status, attributeData) {
|
|
18195
18607
|
const types = [];
|
|
18196
18608
|
const attributes = [];
|
|
18197
18609
|
const enums = [];
|
|
@@ -18208,17 +18620,170 @@ async function compileAttributeGetter(workspace, status, attributeData) {
|
|
|
18208
18620
|
}) ?? null;
|
|
18209
18621
|
const { raw } = await fetchProjectDocument(workspace);
|
|
18210
18622
|
if (typeof raw.project !== "object" || raw.project === null) {
|
|
18211
|
-
throw new Error(
|
|
18623
|
+
throw new Error(
|
|
18624
|
+
"Cannot compile NeoScript property: project record is unavailable."
|
|
18625
|
+
);
|
|
18212
18626
|
}
|
|
18213
|
-
|
|
18214
|
-
|
|
18215
|
-
attributes
|
|
18216
|
-
|
|
18217
|
-
|
|
18218
|
-
|
|
18219
|
-
|
|
18220
|
-
|
|
18221
|
-
|
|
18627
|
+
const returnTypeInfo = resolveNSPropertyReturnTypeInfo(
|
|
18628
|
+
attributeData,
|
|
18629
|
+
attributes
|
|
18630
|
+
);
|
|
18631
|
+
const next = { ...attributeData };
|
|
18632
|
+
if (typeof attributeData.code === "string") {
|
|
18633
|
+
next.getter = compileNSGetter(attributeData.code, {
|
|
18634
|
+
project: raw.project,
|
|
18635
|
+
attributes,
|
|
18636
|
+
types,
|
|
18637
|
+
enums,
|
|
18638
|
+
thisType,
|
|
18639
|
+
returnTypeInfo,
|
|
18640
|
+
dialogueContext: null
|
|
18641
|
+
});
|
|
18642
|
+
} else {
|
|
18643
|
+
delete next.getter;
|
|
18644
|
+
}
|
|
18645
|
+
if (typeof attributeData.setterCode === "string") {
|
|
18646
|
+
next.setter = compileNSSetter(attributeData.setterCode, {
|
|
18647
|
+
project: raw.project,
|
|
18648
|
+
attributes,
|
|
18649
|
+
types,
|
|
18650
|
+
enums,
|
|
18651
|
+
thisType,
|
|
18652
|
+
valueTypeInfo: returnTypeInfo
|
|
18653
|
+
});
|
|
18654
|
+
} else {
|
|
18655
|
+
delete next.setter;
|
|
18656
|
+
}
|
|
18657
|
+
return next;
|
|
18658
|
+
}
|
|
18659
|
+
function prepareNSPropertySetterChanges(workspace, status) {
|
|
18660
|
+
const attributes = /* @__PURE__ */ new Map();
|
|
18661
|
+
for (const record of status.reconstructed.values()) {
|
|
18662
|
+
if (record.recordKind !== "attribute") continue;
|
|
18663
|
+
if (typeof record.fullData.id !== "string") continue;
|
|
18664
|
+
attributes.set(record.fullData.id, record.fullData);
|
|
18665
|
+
}
|
|
18666
|
+
const changesById = /* @__PURE__ */ new Map();
|
|
18667
|
+
for (const change of status.changes) {
|
|
18668
|
+
if (change.recordKind !== "attribute") continue;
|
|
18669
|
+
changesById.set(change.recordId, change);
|
|
18670
|
+
if (change.nextData === void 0) continue;
|
|
18671
|
+
if (change.nextData.type === 10) {
|
|
18672
|
+
if (typeof change.nextData.code !== "string") {
|
|
18673
|
+
delete change.nextData.getter;
|
|
18674
|
+
}
|
|
18675
|
+
if (typeof change.nextData.setterCode !== "string") {
|
|
18676
|
+
delete change.nextData.setter;
|
|
18677
|
+
}
|
|
18678
|
+
}
|
|
18679
|
+
attributes.set(change.recordId, change.nextData);
|
|
18680
|
+
}
|
|
18681
|
+
const removedDeclarations = status.changes.filter(
|
|
18682
|
+
(change) => change.recordKind === "attribute" && change.nextData?.type === 10 && isObjectRecord2(change.baseData) && typeof change.baseData.setterCode === "string" && typeof change.nextData.setterCode !== "string" && !ancestorDeclaresSetter(change.nextData, attributes)
|
|
18683
|
+
).map((change) => change.recordId);
|
|
18684
|
+
for (const declarationId of removedDeclarations) {
|
|
18685
|
+
for (const [attributeId, attribute] of attributes) {
|
|
18686
|
+
if (attributeId === declarationId) continue;
|
|
18687
|
+
if (!attributeDescendsFrom(attribute, declarationId, attributes)) {
|
|
18688
|
+
continue;
|
|
18689
|
+
}
|
|
18690
|
+
if (typeof attribute.setterCode !== "string" && attribute.setter === void 0) {
|
|
18691
|
+
continue;
|
|
18692
|
+
}
|
|
18693
|
+
const next = { ...attribute };
|
|
18694
|
+
delete next.setterCode;
|
|
18695
|
+
delete next.setter;
|
|
18696
|
+
attributes.set(attributeId, next);
|
|
18697
|
+
const key = recordStateKey("attribute", attributeId);
|
|
18698
|
+
const reconstructed = status.reconstructed.get(key);
|
|
18699
|
+
if (reconstructed !== void 0) reconstructed.fullData = next;
|
|
18700
|
+
const existingChange = changesById.get(attributeId);
|
|
18701
|
+
if (existingChange !== void 0) {
|
|
18702
|
+
existingChange.nextData = next;
|
|
18703
|
+
continue;
|
|
18704
|
+
}
|
|
18705
|
+
const base = workspace.state.records[key];
|
|
18706
|
+
if (base === void 0 || reconstructed === void 0) {
|
|
18707
|
+
throw new Error(
|
|
18708
|
+
`Cannot cascade removal of NeoScript property setter to override "${attributeId}": its working-copy state is missing.`
|
|
18709
|
+
);
|
|
18710
|
+
}
|
|
18711
|
+
const cascadeChange = {
|
|
18712
|
+
kind: "update",
|
|
18713
|
+
recordKind: "attribute",
|
|
18714
|
+
recordId: attributeId,
|
|
18715
|
+
file: reconstructed.file,
|
|
18716
|
+
nextData: next,
|
|
18717
|
+
baseData: base.data,
|
|
18718
|
+
baseContentHash: base.contentHash,
|
|
18719
|
+
casBaseHash: base.conflictServerHash ?? base.contentHash
|
|
18720
|
+
};
|
|
18721
|
+
status.changes.push(cascadeChange);
|
|
18722
|
+
changesById.set(attributeId, cascadeChange);
|
|
18723
|
+
}
|
|
18724
|
+
}
|
|
18725
|
+
for (const attribute of attributes.values()) {
|
|
18726
|
+
if (attribute.type !== 10) continue;
|
|
18727
|
+
if (typeof attribute.extendsAttributeId !== "string") continue;
|
|
18728
|
+
if (typeof attribute.setterCode !== "string") continue;
|
|
18729
|
+
if (ancestorDeclaresSetter(attribute, attributes)) continue;
|
|
18730
|
+
throw new Error(
|
|
18731
|
+
`Override NeoScript property "${String(attribute.name ?? attribute.id)}" cannot add a setter because its base chain does not declare one.`
|
|
18732
|
+
);
|
|
18733
|
+
}
|
|
18734
|
+
}
|
|
18735
|
+
function ancestorDeclaresSetter(attribute, attributes) {
|
|
18736
|
+
let parentId = typeof attribute.extendsAttributeId === "string" ? attribute.extendsAttributeId : null;
|
|
18737
|
+
const visited = /* @__PURE__ */ new Set();
|
|
18738
|
+
while (parentId !== null) {
|
|
18739
|
+
if (visited.has(parentId)) {
|
|
18740
|
+
throw new Error(
|
|
18741
|
+
`Cannot resolve NeoScript property setter inheritance: circular attribute chain at "${parentId}".`
|
|
18742
|
+
);
|
|
18743
|
+
}
|
|
18744
|
+
visited.add(parentId);
|
|
18745
|
+
const parent = attributes.get(parentId);
|
|
18746
|
+
if (parent === void 0) {
|
|
18747
|
+
throw new Error(
|
|
18748
|
+
`Cannot resolve NeoScript property setter inheritance: missing parent attribute "${parentId}".`
|
|
18749
|
+
);
|
|
18750
|
+
}
|
|
18751
|
+
if (typeof parent.setterCode === "string") return true;
|
|
18752
|
+
parentId = typeof parent.extendsAttributeId === "string" ? parent.extendsAttributeId : null;
|
|
18753
|
+
}
|
|
18754
|
+
return false;
|
|
18755
|
+
}
|
|
18756
|
+
function attributeDescendsFrom(attribute, ancestorId, attributes) {
|
|
18757
|
+
let parentId = typeof attribute.extendsAttributeId === "string" ? attribute.extendsAttributeId : null;
|
|
18758
|
+
const visited = /* @__PURE__ */ new Set();
|
|
18759
|
+
while (parentId !== null) {
|
|
18760
|
+
if (parentId === ancestorId) return true;
|
|
18761
|
+
if (visited.has(parentId)) return false;
|
|
18762
|
+
visited.add(parentId);
|
|
18763
|
+
const parent = attributes.get(parentId);
|
|
18764
|
+
if (parent === void 0) return false;
|
|
18765
|
+
parentId = typeof parent.extendsAttributeId === "string" ? parent.extendsAttributeId : null;
|
|
18766
|
+
}
|
|
18767
|
+
return false;
|
|
18768
|
+
}
|
|
18769
|
+
function resolveNSPropertyReturnTypeInfo(attribute, attributes) {
|
|
18770
|
+
let current = attribute;
|
|
18771
|
+
const visited = /* @__PURE__ */ new Set();
|
|
18772
|
+
while (current !== void 0) {
|
|
18773
|
+
if (current.returnTypeInfo !== void 0) return current.returnTypeInfo;
|
|
18774
|
+
const parentId = current.extendsAttributeId;
|
|
18775
|
+
if (typeof parentId !== "string") break;
|
|
18776
|
+
if (visited.has(parentId)) {
|
|
18777
|
+
throw new Error(
|
|
18778
|
+
`Cannot compile NeoScript property "${String(attribute.id)}": circular attribute inheritance at "${parentId}".`
|
|
18779
|
+
);
|
|
18780
|
+
}
|
|
18781
|
+
visited.add(parentId);
|
|
18782
|
+
current = attributes.find((candidate) => candidate.id === parentId);
|
|
18783
|
+
}
|
|
18784
|
+
throw new Error(
|
|
18785
|
+
`Cannot compile NeoScript property "${String(attribute.id)}": its returnTypeInfo could not be resolved from the base chain.`
|
|
18786
|
+
);
|
|
18222
18787
|
}
|
|
18223
18788
|
function compileMigrationAction(status, migrationData) {
|
|
18224
18789
|
const types = [];
|
|
@@ -18301,7 +18866,7 @@ async function runDev(workspace, options) {
|
|
|
18301
18866
|
try {
|
|
18302
18867
|
refreshState();
|
|
18303
18868
|
console.log(`[dev] ${label} \u2014 pulling...`);
|
|
18304
|
-
await runPull(workspace, { force: false });
|
|
18869
|
+
await runPull(workspace, { force: false, reset: false });
|
|
18305
18870
|
if (pendingSignalHash !== null) {
|
|
18306
18871
|
workspace.state.headTransactionHash = pendingSignalHash;
|
|
18307
18872
|
lastSeenHash = pendingSignalHash;
|
|
@@ -18635,11 +19200,7 @@ async function runWhoami(apiBaseUrl) {
|
|
|
18635
19200
|
console.log(`Signed in as ${name} <${email}> at ${apiBaseUrl}`);
|
|
18636
19201
|
}
|
|
18637
19202
|
|
|
18638
|
-
// src/
|
|
18639
|
-
init_status();
|
|
18640
|
-
init_workspace();
|
|
18641
|
-
init_ui();
|
|
18642
|
-
var DEFAULT_API_BASE_URL = "https://app.neocompose.com";
|
|
19203
|
+
// src/args.ts
|
|
18643
19204
|
var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
18644
19205
|
"dry-run",
|
|
18645
19206
|
"json",
|
|
@@ -18655,7 +19216,52 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
|
18655
19216
|
"migrate",
|
|
18656
19217
|
"server",
|
|
18657
19218
|
"replace",
|
|
18658
|
-
"
|
|
19219
|
+
"reset",
|
|
19220
|
+
"generate-ids",
|
|
19221
|
+
"help"
|
|
19222
|
+
]);
|
|
19223
|
+
var KNOWN_FLAGS = /* @__PURE__ */ new Set([
|
|
19224
|
+
"accept-bump",
|
|
19225
|
+
"all",
|
|
19226
|
+
"api",
|
|
19227
|
+
"attribute",
|
|
19228
|
+
"bump",
|
|
19229
|
+
"commit",
|
|
19230
|
+
"dir",
|
|
19231
|
+
"dry-run",
|
|
19232
|
+
"entries",
|
|
19233
|
+
"file",
|
|
19234
|
+
"force",
|
|
19235
|
+
"from",
|
|
19236
|
+
"generate-ids",
|
|
19237
|
+
"help",
|
|
19238
|
+
"into",
|
|
19239
|
+
"json",
|
|
19240
|
+
"key",
|
|
19241
|
+
"kind",
|
|
19242
|
+
"migrate",
|
|
19243
|
+
"mine",
|
|
19244
|
+
"mode",
|
|
19245
|
+
"out",
|
|
19246
|
+
"profile",
|
|
19247
|
+
"project",
|
|
19248
|
+
"push",
|
|
19249
|
+
"replace",
|
|
19250
|
+
"reset",
|
|
19251
|
+
"returns",
|
|
19252
|
+
"save",
|
|
19253
|
+
"save-project",
|
|
19254
|
+
"server",
|
|
19255
|
+
"skip-invalid",
|
|
19256
|
+
"status",
|
|
19257
|
+
"summary",
|
|
19258
|
+
"target",
|
|
19259
|
+
"template",
|
|
19260
|
+
"theirs",
|
|
19261
|
+
"this",
|
|
19262
|
+
"token-stdin",
|
|
19263
|
+
"type",
|
|
19264
|
+
"version"
|
|
18659
19265
|
]);
|
|
18660
19266
|
function parseArgs(argv) {
|
|
18661
19267
|
const [command = null, ...rest] = argv;
|
|
@@ -18689,6 +19295,19 @@ function stringFlag(args, name) {
|
|
|
18689
19295
|
function boolFlag(args, name) {
|
|
18690
19296
|
return args.flags.get(name) === true;
|
|
18691
19297
|
}
|
|
19298
|
+
function assertKnownFlags(args) {
|
|
19299
|
+
for (const name of args.flags.keys()) {
|
|
19300
|
+
if (KNOWN_FLAGS.has(name)) continue;
|
|
19301
|
+
const hint = args.command === null ? "Run `neo help` for usage." : `Run \`neo ${args.command} --help\` for usage.`;
|
|
19302
|
+
throw new Error(`Unknown flag "--${name}". ${hint}`);
|
|
19303
|
+
}
|
|
19304
|
+
}
|
|
19305
|
+
|
|
19306
|
+
// src/main.ts
|
|
19307
|
+
init_status();
|
|
19308
|
+
init_workspace();
|
|
19309
|
+
init_ui();
|
|
19310
|
+
var DEFAULT_API_BASE_URL = "http://localhost:3000";
|
|
18692
19311
|
function profileFlag(args) {
|
|
18693
19312
|
const value = stringFlag(args, "profile");
|
|
18694
19313
|
if (value === null) return null;
|
|
@@ -18717,7 +19336,7 @@ ${h("Start")}
|
|
|
18717
19336
|
whoami ${d("[--api <url>]")}
|
|
18718
19337
|
|
|
18719
19338
|
${h("Working copy")}
|
|
18720
|
-
pull ${d("[--force]")}
|
|
19339
|
+
pull ${d("[--force|--reset]")} push ${d("[--dry-run] [--summary <text>] [--accept-bump]")}
|
|
18721
19340
|
status ${d("[--json]")} diff ${d("[--json]")}
|
|
18722
19341
|
dev ${d("[--push]")} resolve ${d("[--mine|--theirs]")}
|
|
18723
19342
|
|
|
@@ -18731,13 +19350,58 @@ ${h("Content & scripts")}
|
|
|
18731
19350
|
values ${d("list | get | set | create | delete | ...")} loc ${d("locales | list | set | archive | restore | ...")}
|
|
18732
19351
|
dialogue ${d("list | show | node | group | priority-group")}
|
|
18733
19352
|
records ${d("get | query")} files ${d("list | delete")}
|
|
18734
|
-
script ${d("check | eval | apply
|
|
19353
|
+
script ${d("check | eval | apply | compile [--mode getter|action|setter] [--attribute <id-or-name>]")}
|
|
19354
|
+
migrate ${d("new | list | check | run | prune")}
|
|
18735
19355
|
|
|
18736
19356
|
Run any command with missing arguments in a terminal and ${h("neo")} will ask.
|
|
18737
19357
|
`;
|
|
18738
19358
|
}
|
|
19359
|
+
function commandHelp(command) {
|
|
19360
|
+
const h = color.bold;
|
|
19361
|
+
const d = color.dim;
|
|
19362
|
+
if (command === "pull") {
|
|
19363
|
+
return `${h("neo pull")} \u2014 synchronize the schema working copy
|
|
19364
|
+
|
|
19365
|
+
${h("Usage")}
|
|
19366
|
+
neo pull ${d("[--force|--reset]")}
|
|
19367
|
+
|
|
19368
|
+
${h("Flags")}
|
|
19369
|
+
--force ${d("Discard local edits and take the current server schema.")}
|
|
19370
|
+
--reset ${d("Destructively regenerate the entire working copy and schema marker scaffold, even when the sync head is unchanged.")}
|
|
19371
|
+
|
|
19372
|
+
Use ${h("--reset")} for schema-vocabulary upgrades such as NeoGetter \u2192
|
|
19373
|
+
NeoProperty. It does not attempt to parse the old generated marker files.
|
|
19374
|
+
`;
|
|
19375
|
+
}
|
|
19376
|
+
if (command === "push") {
|
|
19377
|
+
return `${h("neo push")} \u2014 commit the working copy to the server
|
|
19378
|
+
|
|
19379
|
+
${h("Usage")}
|
|
19380
|
+
neo push ${d("[--dry-run] [--summary <text>] [--accept-bump]")}
|
|
19381
|
+
|
|
19382
|
+
${h("Flags")}
|
|
19383
|
+
--dry-run ${d("Preview the change set; commit nothing.")}
|
|
19384
|
+
--summary <text> ${d("Attach a summary message to the transaction.")}
|
|
19385
|
+
--accept-bump ${d("Accept a server-required version bump instead of aborting.")}
|
|
19386
|
+
|
|
19387
|
+
Push sends the ${h("entire")} working copy as one atomic compare-and-swap
|
|
19388
|
+
transaction. Run ${h("neo status")} / ${h("neo diff")} first \u2014 local-ahead changes
|
|
19389
|
+
you did not make this session ride along too.
|
|
19390
|
+
`;
|
|
19391
|
+
}
|
|
19392
|
+
return usage();
|
|
19393
|
+
}
|
|
18739
19394
|
async function main() {
|
|
18740
19395
|
const args = parseArgs(process.argv.slice(2));
|
|
19396
|
+
if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
|
|
19397
|
+
console.log(usage());
|
|
19398
|
+
return;
|
|
19399
|
+
}
|
|
19400
|
+
if (boolFlag(args, "help")) {
|
|
19401
|
+
console.log(commandHelp(args.command));
|
|
19402
|
+
return;
|
|
19403
|
+
}
|
|
19404
|
+
assertKnownFlags(args);
|
|
18741
19405
|
const apiBaseUrl = stringFlag(args, "api") ?? DEFAULT_API_BASE_URL;
|
|
18742
19406
|
switch (args.command) {
|
|
18743
19407
|
case "login":
|
|
@@ -18766,7 +19430,10 @@ async function main() {
|
|
|
18766
19430
|
case "pull": {
|
|
18767
19431
|
const workspace = loadWorkspaceForCommand(args);
|
|
18768
19432
|
const { runPull: runPull2 } = await Promise.resolve().then(() => (init_pull(), pull_exports));
|
|
18769
|
-
await runPull2(workspace, {
|
|
19433
|
+
await runPull2(workspace, {
|
|
19434
|
+
force: boolFlag(args, "force"),
|
|
19435
|
+
reset: boolFlag(args, "reset")
|
|
19436
|
+
});
|
|
18770
19437
|
return;
|
|
18771
19438
|
}
|
|
18772
19439
|
case "branch": {
|
|
@@ -18935,11 +19602,18 @@ async function main() {
|
|
|
18935
19602
|
);
|
|
18936
19603
|
}
|
|
18937
19604
|
const { runScript: runScript2 } = await Promise.resolve().then(() => (init_script(), script_exports));
|
|
19605
|
+
const requestedMode = stringFlag(args, "mode") ?? "getter";
|
|
19606
|
+
if (requestedMode !== "getter" && requestedMode !== "action" && requestedMode !== "setter") {
|
|
19607
|
+
throw new Error(
|
|
19608
|
+
`--mode must be getter, action, or setter; received "${requestedMode}".`
|
|
19609
|
+
);
|
|
19610
|
+
}
|
|
18938
19611
|
await runScript2(workspace, sub, {
|
|
18939
|
-
mode:
|
|
19612
|
+
mode: requestedMode,
|
|
18940
19613
|
source: args.positional[1] ?? null,
|
|
18941
19614
|
file: stringFlag(args, "file"),
|
|
18942
19615
|
thisRef: stringFlag(args, "this"),
|
|
19616
|
+
attributeRef: stringFlag(args, "attribute"),
|
|
18943
19617
|
returns: stringFlag(args, "returns"),
|
|
18944
19618
|
all: boolFlag(args, "all"),
|
|
18945
19619
|
json: boolFlag(args, "json"),
|
|
@@ -19089,10 +19763,6 @@ async function main() {
|
|
|
19089
19763
|
}
|
|
19090
19764
|
return;
|
|
19091
19765
|
}
|
|
19092
|
-
case null:
|
|
19093
|
-
case "help":
|
|
19094
|
-
console.log(usage());
|
|
19095
|
-
return;
|
|
19096
19766
|
default:
|
|
19097
19767
|
console.error(`Unknown command "${args.command}".
|
|
19098
19768
|
`);
|