@open-core/framework 0.3.1 → 0.3.2
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/runtime/server/decorators/command.d.ts +2 -0
- package/dist/runtime/server/decorators/command.js +4 -1
- package/dist/runtime/server/helpers/command-validation.helper.js +12 -1
- package/dist/runtime/server/helpers/function-helper.d.ts +5 -0
- package/dist/runtime/server/helpers/function-helper.js +17 -0
- package/dist/runtime/server/helpers/process-tuple-schema.js +26 -15
- package/package.json +1 -1
|
@@ -34,6 +34,8 @@ export interface CommandMetadata extends CommandConfig {
|
|
|
34
34
|
isPublic?: boolean;
|
|
35
35
|
/** Security metadata for remote validation */
|
|
36
36
|
security?: SecurityMetadata;
|
|
37
|
+
/** True if the last parameter uses the spread operator (...args) */
|
|
38
|
+
hasSpreadParam?: boolean;
|
|
37
39
|
}
|
|
38
40
|
type ServerCommandHandler = (() => any) | ((player: Player, ...args: any[]) => any);
|
|
39
41
|
/**
|
|
@@ -24,9 +24,12 @@ function Command(configOrName, schema) {
|
|
|
24
24
|
throw new Error(`@Command '${config.command}': first parameter must be Player if parameters are present`);
|
|
25
25
|
}
|
|
26
26
|
const paramNames = (0, function_helper_1.getParameterNames)(descriptor.value);
|
|
27
|
+
const spreadIndices = (0, function_helper_1.getSpreadParameterIndices)(descriptor.value);
|
|
28
|
+
const hasSpreadParam = spreadIndices.length > 0 && spreadIndices[spreadIndices.length - 1];
|
|
27
29
|
const metadata = Object.assign(Object.assign({}, config), { methodName: propertyKey, target: target.constructor, paramTypes,
|
|
28
30
|
paramNames,
|
|
29
|
-
expectsPlayer
|
|
31
|
+
expectsPlayer,
|
|
32
|
+
hasSpreadParam });
|
|
30
33
|
Reflect.defineMetadata(metadata_server_keys_1.METADATA_KEYS.COMMAND, metadata, target, propertyKey);
|
|
31
34
|
};
|
|
32
35
|
}
|
|
@@ -61,7 +61,18 @@ async function validateAndExecuteCommand(meta, player, args, handler) {
|
|
|
61
61
|
usage: meta.usage,
|
|
62
62
|
});
|
|
63
63
|
});
|
|
64
|
-
|
|
64
|
+
const finalArgs = validated;
|
|
65
|
+
// If the handler uses spread operator (...args), flatten the last array argument
|
|
66
|
+
// so the handler receives individual arguments instead of a single array.
|
|
67
|
+
if (meta.hasSpreadParam &&
|
|
68
|
+
finalArgs.length > 0 &&
|
|
69
|
+
Array.isArray(finalArgs[finalArgs.length - 1])) {
|
|
70
|
+
const positional = finalArgs.slice(0, finalArgs.length - 1);
|
|
71
|
+
const rest = finalArgs[finalArgs.length - 1];
|
|
72
|
+
return await handler(player, ...positional, ...rest);
|
|
73
|
+
}
|
|
74
|
+
// For regular array parameters (args: string[]), pass as-is
|
|
75
|
+
return await handler(player, ...finalArgs);
|
|
65
76
|
}
|
|
66
77
|
// fallback
|
|
67
78
|
return await handler(player);
|
|
@@ -1 +1,6 @@
|
|
|
1
1
|
export declare function getParameterNames(func: (...args: any[]) => any): string[];
|
|
2
|
+
/**
|
|
3
|
+
* Detects which parameter indices use the spread operator (...args).
|
|
4
|
+
* Returns an array of booleans where true means the parameter at that index is a spread parameter.
|
|
5
|
+
*/
|
|
6
|
+
export declare function getSpreadParameterIndices(func: (...args: any[]) => any): boolean[];
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getParameterNames = getParameterNames;
|
|
4
|
+
exports.getSpreadParameterIndices = getSpreadParameterIndices;
|
|
4
5
|
function getParameterNames(func) {
|
|
5
6
|
const stripped = func
|
|
6
7
|
.toString()
|
|
@@ -13,3 +14,19 @@ function getParameterNames(func) {
|
|
|
13
14
|
.filter(Boolean);
|
|
14
15
|
return args;
|
|
15
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Detects which parameter indices use the spread operator (...args).
|
|
19
|
+
* Returns an array of booleans where true means the parameter at that index is a spread parameter.
|
|
20
|
+
*/
|
|
21
|
+
function getSpreadParameterIndices(func) {
|
|
22
|
+
const stripped = func
|
|
23
|
+
.toString()
|
|
24
|
+
.replace(/\/\/.*$/gm, '')
|
|
25
|
+
.replace(/\/\*[\s\S]*?\*\//gm, '');
|
|
26
|
+
const argsString = stripped.slice(stripped.indexOf('(') + 1, stripped.indexOf(')'));
|
|
27
|
+
const args = argsString
|
|
28
|
+
.split(',')
|
|
29
|
+
.map((arg) => arg.trim())
|
|
30
|
+
.filter(Boolean);
|
|
31
|
+
return args.map((arg) => arg.startsWith('...'));
|
|
32
|
+
}
|
|
@@ -28,24 +28,35 @@ function processTupleSchema(schema, args) {
|
|
|
28
28
|
if (items.length === 0) {
|
|
29
29
|
return args;
|
|
30
30
|
}
|
|
31
|
-
// Only process if we have MORE args than schema expects
|
|
32
|
-
// This means we need to group extra args into the last position
|
|
33
|
-
if (args.length <= items.length) {
|
|
34
|
-
return args;
|
|
35
|
-
}
|
|
36
31
|
const lastItem = items[items.length - 1];
|
|
37
32
|
const positionalCount = items.length - 1;
|
|
38
|
-
//
|
|
39
|
-
if (
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
33
|
+
// Case: More args than items (Greedy grouping)
|
|
34
|
+
if (args.length > items.length) {
|
|
35
|
+
// If last parameter is a string, join extra args with space
|
|
36
|
+
if (lastItem instanceof zod_1.default.ZodString) {
|
|
37
|
+
const positional = args.slice(0, positionalCount);
|
|
38
|
+
const restString = args.slice(positionalCount).join(' ');
|
|
39
|
+
return [...positional, restString];
|
|
40
|
+
}
|
|
41
|
+
// If last parameter is an array, we keep them as individual elements
|
|
42
|
+
// for the handler's spread operator (...args) or just as the array itself
|
|
43
|
+
// if ZodTuple is being used to parse.
|
|
44
|
+
// However, to avoid nesting [arg1, [arg2, arg3]], we return them flat
|
|
45
|
+
// if the handler expects a spread, OR we return the array if it's a single param.
|
|
46
|
+
if (lastItem instanceof zod_1.default.ZodArray) {
|
|
47
|
+
// For ZodTuple.parse() to work with a ZodArray at the end,
|
|
48
|
+
// it actually expects the array as a single element in that position.
|
|
49
|
+
const positional = args.slice(0, positionalCount);
|
|
50
|
+
const restArray = args.slice(positionalCount);
|
|
51
|
+
return [...positional, restArray];
|
|
52
|
+
}
|
|
43
53
|
}
|
|
44
|
-
//
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
54
|
+
// Case: Exact match but last is array
|
|
55
|
+
if (args.length === items.length) {
|
|
56
|
+
if (lastItem instanceof zod_1.default.ZodArray && !Array.isArray(args[positionalCount])) {
|
|
57
|
+
const positional = args.slice(0, positionalCount);
|
|
58
|
+
return [...positional, [args[positionalCount]]];
|
|
59
|
+
}
|
|
49
60
|
}
|
|
50
61
|
return args;
|
|
51
62
|
}
|