@amxts/core 0.1.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/LICENSE +21 -0
- package/README.md +162 -0
- package/README.ru.md +162 -0
- package/amxmodx/base/include/amxconst.inc +594 -0
- package/amxmodx/base/include/amxmisc.inc +902 -0
- package/amxmodx/base/include/amxmodx.inc +3447 -0
- package/amxmodx/base/include/amxmodx_version.inc +20 -0
- package/amxmodx/base/include/cellarray.inc +525 -0
- package/amxmodx/base/include/cellstack.inc +166 -0
- package/amxmodx/base/include/celltrie.inc +412 -0
- package/amxmodx/base/include/core.inc +202 -0
- package/amxmodx/base/include/csstats.inc +298 -0
- package/amxmodx/base/include/csstats_const.inc +29 -0
- package/amxmodx/base/include/cstrike.inc +1287 -0
- package/amxmodx/base/include/cstrike_const.inc +521 -0
- package/amxmodx/base/include/csx.inc +259 -0
- package/amxmodx/base/include/cvars.inc +547 -0
- package/amxmodx/base/include/datapack.inc +161 -0
- package/amxmodx/base/include/dbi.inc +154 -0
- package/amxmodx/base/include/dodconst.inc +152 -0
- package/amxmodx/base/include/dodfun.inc +152 -0
- package/amxmodx/base/include/dodstats.inc +69 -0
- package/amxmodx/base/include/dodx.inc +161 -0
- package/amxmodx/base/include/engine.inc +1343 -0
- package/amxmodx/base/include/engine_const.inc +310 -0
- package/amxmodx/base/include/engine_stocks.inc +248 -0
- package/amxmodx/base/include/esf.inc +70 -0
- package/amxmodx/base/include/esf_const.inc +74 -0
- package/amxmodx/base/include/fakemeta.inc +1127 -0
- package/amxmodx/base/include/fakemeta_const.inc +793 -0
- package/amxmodx/base/include/fakemeta_stocks.inc +395 -0
- package/amxmodx/base/include/fakemeta_util.inc +882 -0
- package/amxmodx/base/include/file.inc +666 -0
- package/amxmodx/base/include/float.inc +422 -0
- package/amxmodx/base/include/fun.inc +333 -0
- package/amxmodx/base/include/gameconfig.inc +93 -0
- package/amxmodx/base/include/geoip.inc +264 -0
- package/amxmodx/base/include/ham_const.inc +4352 -0
- package/amxmodx/base/include/hamsandwich.inc +439 -0
- package/amxmodx/base/include/hlsdk_const.inc +808 -0
- package/amxmodx/base/include/json.inc +777 -0
- package/amxmodx/base/include/lang.inc +119 -0
- package/amxmodx/base/include/message_const.inc +1130 -0
- package/amxmodx/base/include/message_stocks.inc +161 -0
- package/amxmodx/base/include/messages.inc +604 -0
- package/amxmodx/base/include/newmenus.inc +387 -0
- package/amxmodx/base/include/ns.inc +754 -0
- package/amxmodx/base/include/ns_const.inc +196 -0
- package/amxmodx/base/include/nvault.inc +154 -0
- package/amxmodx/base/include/regex.inc +348 -0
- package/amxmodx/base/include/sockets.inc +183 -0
- package/amxmodx/base/include/sorting.inc +107 -0
- package/amxmodx/base/include/sqlx.inc +582 -0
- package/amxmodx/base/include/string.inc +786 -0
- package/amxmodx/base/include/string_const.inc +156 -0
- package/amxmodx/base/include/string_stocks.inc +325 -0
- package/amxmodx/base/include/textparse_ini.inc +214 -0
- package/amxmodx/base/include/textparse_smc.inc +261 -0
- package/amxmodx/base/include/tfcconst.inc +84 -0
- package/amxmodx/base/include/tfcstats.inc +62 -0
- package/amxmodx/base/include/tfcx.inc +148 -0
- package/amxmodx/base/include/time.inc +118 -0
- package/amxmodx/base/include/tsconst.inc +154 -0
- package/amxmodx/base/include/tsfun.inc +198 -0
- package/amxmodx/base/include/tsstats.inc +65 -0
- package/amxmodx/base/include/tsx.inc +88 -0
- package/amxmodx/base/include/vault.inc +60 -0
- package/amxmodx/base/include/vector.inc +131 -0
- package/amxmodx/base/include/xs.inc +1570 -0
- package/as/amxts.d.ts +153 -0
- package/as/constants.ts +4730 -0
- package/as/effects.ts +1449 -0
- package/as/entities.ts +5482 -0
- package/as/events.ts +3054 -0
- package/as/facade.ts +4639 -0
- package/as/flags.ts +299 -0
- package/as/fs.ts +287 -0
- package/as/hooks.ts +18536 -0
- package/as/kit.ts +25 -0
- package/as/lib/check.ts +86 -0
- package/as/modules/http.ts +184 -0
- package/as/natives.ts +11845 -0
- package/as/os.ts +30 -0
- package/as/promise.ts +1392 -0
- package/as/promise.types.d.ts +82 -0
- package/as/remote.ts +288 -0
- package/as/tsconfig.json +22 -0
- package/as/vector.ts +65 -0
- package/bin/amxts.mjs +10 -0
- package/includes/menu_core.inc +355 -0
- package/includes/order.txt +54 -0
- package/includes/sources.json +27 -0
- package/includes/universal_config.inc +355 -0
- package/lint/oxlint-plugin.mjs +77 -0
- package/node_modules/assemblyscript/LICENSE +201 -0
- package/node_modules/assemblyscript/NOTICE +93 -0
- package/node_modules/assemblyscript/package.json +63 -0
- package/node_modules/assemblyscript/std/README.md +6 -0
- package/node_modules/assemblyscript/std/assembly/array.ts +526 -0
- package/node_modules/assemblyscript/std/assembly/arraybuffer.ts +77 -0
- package/node_modules/assemblyscript/std/assembly/atomics.ts +127 -0
- package/node_modules/assemblyscript/std/assembly/bindings/asyncify.ts +16 -0
- package/node_modules/assemblyscript/std/assembly/bindings/dom.ts +291 -0
- package/node_modules/assemblyscript/std/assembly/bindings/node.ts +6 -0
- package/node_modules/assemblyscript/std/assembly/builtins.ts +2631 -0
- package/node_modules/assemblyscript/std/assembly/compat.ts +2 -0
- package/node_modules/assemblyscript/std/assembly/console.ts +42 -0
- package/node_modules/assemblyscript/std/assembly/crypto.ts +9 -0
- package/node_modules/assemblyscript/std/assembly/dataview.ts +181 -0
- package/node_modules/assemblyscript/std/assembly/date.ts +373 -0
- package/node_modules/assemblyscript/std/assembly/diagnostics.ts +11 -0
- package/node_modules/assemblyscript/std/assembly/error.ts +44 -0
- package/node_modules/assemblyscript/std/assembly/function.ts +38 -0
- package/node_modules/assemblyscript/std/assembly/index.d.ts +2822 -0
- package/node_modules/assemblyscript/std/assembly/iterator.ts +35 -0
- package/node_modules/assemblyscript/std/assembly/map.ts +260 -0
- package/node_modules/assemblyscript/std/assembly/math.ts +3289 -0
- package/node_modules/assemblyscript/std/assembly/memory.ts +123 -0
- package/node_modules/assemblyscript/std/assembly/number.ts +388 -0
- package/node_modules/assemblyscript/std/assembly/object.ts +36 -0
- package/node_modules/assemblyscript/std/assembly/performance.ts +9 -0
- package/node_modules/assemblyscript/std/assembly/polyfills.ts +27 -0
- package/node_modules/assemblyscript/std/assembly/process.ts +50 -0
- package/node_modules/assemblyscript/std/assembly/reference.ts +48 -0
- package/node_modules/assemblyscript/std/assembly/regexp.ts +12 -0
- package/node_modules/assemblyscript/std/assembly/rt/README.md +83 -0
- package/node_modules/assemblyscript/std/assembly/rt/common.ts +81 -0
- package/node_modules/assemblyscript/std/assembly/rt/index-incremental.ts +2 -0
- package/node_modules/assemblyscript/std/assembly/rt/index-minimal.ts +2 -0
- package/node_modules/assemblyscript/std/assembly/rt/index-stub.ts +1 -0
- package/node_modules/assemblyscript/std/assembly/rt/index.d.ts +37 -0
- package/node_modules/assemblyscript/std/assembly/rt/itcms.ts +419 -0
- package/node_modules/assemblyscript/std/assembly/rt/rtrace.ts +15 -0
- package/node_modules/assemblyscript/std/assembly/rt/stub.ts +133 -0
- package/node_modules/assemblyscript/std/assembly/rt/tcms.ts +254 -0
- package/node_modules/assemblyscript/std/assembly/rt/tlsf.ts +592 -0
- package/node_modules/assemblyscript/std/assembly/rt.ts +87 -0
- package/node_modules/assemblyscript/std/assembly/set.ts +220 -0
- package/node_modules/assemblyscript/std/assembly/shared/feature.ts +65 -0
- package/node_modules/assemblyscript/std/assembly/shared/runtime.ts +11 -0
- package/node_modules/assemblyscript/std/assembly/shared/target.ts +11 -0
- package/node_modules/assemblyscript/std/assembly/shared/tsconfig.json +11 -0
- package/node_modules/assemblyscript/std/assembly/shared/typeinfo.ts +72 -0
- package/node_modules/assemblyscript/std/assembly/staticarray.ts +401 -0
- package/node_modules/assemblyscript/std/assembly/string.ts +847 -0
- package/node_modules/assemblyscript/std/assembly/symbol.ts +114 -0
- package/node_modules/assemblyscript/std/assembly/table.ts +16 -0
- package/node_modules/assemblyscript/std/assembly/tsconfig.json +6 -0
- package/node_modules/assemblyscript/std/assembly/typedarray.ts +1945 -0
- package/node_modules/assemblyscript/std/assembly/uri.ts +17 -0
- package/node_modules/assemblyscript/std/assembly/util/bytes.ts +107 -0
- package/node_modules/assemblyscript/std/assembly/util/casemap.ts +497 -0
- package/node_modules/assemblyscript/std/assembly/util/error.ts +54 -0
- package/node_modules/assemblyscript/std/assembly/util/hash.ts +117 -0
- package/node_modules/assemblyscript/std/assembly/util/math.ts +1922 -0
- package/node_modules/assemblyscript/std/assembly/util/memory.ts +290 -0
- package/node_modules/assemblyscript/std/assembly/util/number.ts +873 -0
- package/node_modules/assemblyscript/std/assembly/util/sort.ts +313 -0
- package/node_modules/assemblyscript/std/assembly/util/string.ts +1202 -0
- package/node_modules/assemblyscript/std/assembly/util/uri.ts +275 -0
- package/node_modules/assemblyscript/std/assembly/vector.ts +4 -0
- package/node_modules/assemblyscript/std/assembly.json +16 -0
- package/node_modules/assemblyscript/std/portable/index.d.ts +462 -0
- package/node_modules/assemblyscript/std/portable/index.js +416 -0
- package/node_modules/assemblyscript/std/portable.json +11 -0
- package/node_modules/assemblyscript/std/types/assembly/index.d.ts +1 -0
- package/node_modules/assemblyscript/std/types/assembly/package.json +3 -0
- package/node_modules/assemblyscript/std/types/portable/index.d.ts +1 -0
- package/node_modules/assemblyscript/std/types/portable/package.json +3 -0
- package/node_modules/assemblyscript/tsconfig-base.json +13 -0
- package/package.json +112 -0
- package/runtime/deps/assemblyscript/LICENSE +201 -0
- package/runtime/deps/assemblyscript/NOTICE +93 -0
- package/runtime/deps/assemblyscript/bin/asc.js +35 -0
- package/runtime/deps/assemblyscript/dist/asc.js +25035 -0
- package/runtime/deps/assemblyscript/dist/assemblyscript.js +337 -0
- package/runtime/deps/assemblyscript/node_modules/binaryen/LICENSE +201 -0
- package/runtime/deps/assemblyscript/node_modules/binaryen/index.js +28905 -0
- package/runtime/deps/assemblyscript/node_modules/binaryen/package.json +50 -0
- package/runtime/deps/assemblyscript/node_modules/long/LICENSE +202 -0
- package/runtime/deps/assemblyscript/node_modules/long/index.js +1581 -0
- package/runtime/deps/assemblyscript/node_modules/long/package.json +58 -0
- package/runtime/deps/assemblyscript/package.json +114 -0
- package/runtime/host/amxts.inc +85 -0
- package/runtime/licenses/AMXX-LICENSE.txt +34 -0
- package/runtime/licenses/AssemblyScript-LICENSE +201 -0
- package/runtime/licenses/AssemblyScript-NOTICE +93 -0
- package/runtime/licenses/Binaryen-LICENSE +201 -0
- package/runtime/licenses/Bun-LICENSE.md +84 -0
- package/runtime/licenses/GPL-3.0.txt +674 -0
- package/runtime/licenses/LLVM-LICENSE.TXT +279 -0
- package/runtime/licenses/README.md +25 -0
- package/runtime/licenses/WAMR-LICENSE +219 -0
- package/runtime/natives.txt +1095 -0
- package/runtime/patches/README.md +59 -0
- package/runtime/patches/assemblyscript-0.28.20-amxts.patch +14174 -0
- package/runtime/patches/wamr-2.4.5-amxts.patch +364 -0
- package/scripts/apply-docs.ts +508 -0
- package/scripts/asc.ts +27 -0
- package/scripts/auto-imports.ts +258 -0
- package/scripts/build-wasm.ts +595 -0
- package/scripts/check.ts +93 -0
- package/scripts/compile-cache.ts +179 -0
- package/scripts/compile.ts +401 -0
- package/scripts/docker-server.ts +73 -0
- package/scripts/docs/as/amxts.ts +210 -0
- package/scripts/docs/as/effects.ts +1684 -0
- package/scripts/docs/as/facade.ts +3302 -0
- package/scripts/docs/as/fs.ts +173 -0
- package/scripts/docs/as/lib/check.ts +68 -0
- package/scripts/docs/as/modules/http.ts +66 -0
- package/scripts/docs/as/os.ts +16 -0
- package/scripts/docs/as/promise.ts +132 -0
- package/scripts/docs/as/promise.types.ts +63 -0
- package/scripts/docs/as/vector.ts +48 -0
- package/scripts/docs/entities.ts +2338 -0
- package/scripts/docs/events.ts +245 -0
- package/scripts/docs/game.ts +497 -0
- package/scripts/docs/messages.ts +148 -0
- package/scripts/file-contents.ts +74 -0
- package/scripts/includes.ts +134 -0
- package/scripts/player-fields.ts +866 -0
- package/scripts/plugin-cache.ts +92 -0
- package/scripts/plugin-natives.ts +1157 -0
- package/scripts/prebuilt.ts +268 -0
- package/scripts/prepare.ts +134 -0
- package/scripts/project.ts +973 -0
- package/scripts/run.ts +28 -0
- package/scripts/shared-modules.ts +906 -0
- package/scripts/system.ts +33 -0
- package/scripts/tracked-fs.ts +115 -0
- package/scripts/typed-configs.ts +788 -0
- package/scripts/ui.ts +77 -0
- package/src/cli-api.mjs +175 -0
- package/src/parser/include-parser.ts +506 -0
- package/src/system.mjs +155 -0
- package/src/testing/compile-cache.ts +31 -0
- package/src/testing/compile.ts +222 -0
- package/src/testing/coroutines.ts +191 -0
- package/src/testing/index.ts +39 -0
- package/src/testing/kits.ts +55 -0
- package/src/testing/memory.ts +125 -0
- package/src/testing/natives.ts +925 -0
- package/src/testing/server.ts +1874 -0
- package/src/testing/setup.ts +63 -0
- package/src/testing/tables.ts +139 -0
- package/src/types.ts +51 -0
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
// src/parser/include-parser.ts
|
|
2
|
+
import type {
|
|
3
|
+
Constant,
|
|
4
|
+
EnumDeclaration,
|
|
5
|
+
EnumMember,
|
|
6
|
+
ForwardDeclaration,
|
|
7
|
+
NativeFunction,
|
|
8
|
+
Parameter,
|
|
9
|
+
ParsedInclude,
|
|
10
|
+
} from '../types';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Evaluates a Pawn constant expression, or gives up.
|
|
14
|
+
*
|
|
15
|
+
* Only integer arithmetic a macro expansion leaves behind — `(1024 * 1)`,
|
|
16
|
+
* `1<<3`, `BIT(2)|BIT(3)`. Division is deliberately excluded: Pawn's `/` on
|
|
17
|
+
* cells is not JavaScript's, and a wrong number here is worse than none.
|
|
18
|
+
* Anything with an unresolved identifier in it returns undefined, which stops
|
|
19
|
+
* the enum's auto-increment rather than letting it invent a value.
|
|
20
|
+
*/
|
|
21
|
+
export function evalInt(expr: string): number | undefined {
|
|
22
|
+
if (!/^[\d\s+\-*()<>|&^~]+$/.test(expr)) return undefined;
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
// Only digits and operators got this far: a constant expression, not code.
|
|
26
|
+
// oxlint-disable-next-line no-new-func
|
|
27
|
+
const value = new Function(`return (${expr});`)();
|
|
28
|
+
return typeof value === 'number' && Number.isInteger(value) ? value : undefined;
|
|
29
|
+
} catch {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Pawn's increment clause, `enum E (<<= 1)`: how a member's value gives the next one's. */
|
|
35
|
+
const ENUM_STEP: Record<string, (value: number, by: number) => number> = {
|
|
36
|
+
'+': (value, by) => value + by,
|
|
37
|
+
'*': (value, by) => value * by,
|
|
38
|
+
'<<': (value, by) => value << by,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/** `a, b(c, d), e[1]` as `a`, `b(c, d)`, `e[1]`: commas inside brackets do not split. */
|
|
42
|
+
function splitTopLevel(text: string): string[] {
|
|
43
|
+
const parts: string[] = [];
|
|
44
|
+
let current = '';
|
|
45
|
+
let depth = 0;
|
|
46
|
+
for (const char of text) {
|
|
47
|
+
if (char === '(' || char === '[' || char === '{') {
|
|
48
|
+
depth++;
|
|
49
|
+
} else if (char === ')' || char === ']' || char === '}') {
|
|
50
|
+
depth--;
|
|
51
|
+
} else if (char === ',' && depth === 0) {
|
|
52
|
+
if (current.trim()) parts.push(current.trim());
|
|
53
|
+
current = '';
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
current += char;
|
|
57
|
+
}
|
|
58
|
+
if (current.trim()) parts.push(current.trim());
|
|
59
|
+
return parts;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface Macro {
|
|
63
|
+
params: string[];
|
|
64
|
+
body: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export class IncludeParser {
|
|
68
|
+
private lines: string[];
|
|
69
|
+
private currentLine = 0;
|
|
70
|
+
private macros: Map<string, Macro>;
|
|
71
|
+
|
|
72
|
+
constructor(content: string, macros = new Map<string, Macro>()) {
|
|
73
|
+
this.lines = content.split('\n');
|
|
74
|
+
this.macros = macros;
|
|
75
|
+
IncludeParser.collectMacrosFrom(content, this.macros);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Function-like defines: `#define BIT(%0) (1<<(%0))`.
|
|
80
|
+
* The table is shared across includes because BEGIN_FUNC_REGION is declared
|
|
81
|
+
* in reapi.inc but used in reapi_gamedll_const.inc.
|
|
82
|
+
*/
|
|
83
|
+
static collectMacrosFrom(content: string, into: Map<string, Macro>): Map<string, Macro> {
|
|
84
|
+
for (const line of content.split('\n')) {
|
|
85
|
+
const match = line.trim().match(/^#define\s+(\w+)\(([^)]*)\)\s+(\S.*)$/);
|
|
86
|
+
if (!match) continue;
|
|
87
|
+
|
|
88
|
+
const [, name, params, body] = match;
|
|
89
|
+
into.set(name, {
|
|
90
|
+
params: params.split(',').map(p => p.trim()).filter(Boolean),
|
|
91
|
+
body: body.trim(),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return into;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Expands macro calls; nested calls resolve on a later round. */
|
|
98
|
+
private expand(text: string): string {
|
|
99
|
+
let result = text;
|
|
100
|
+
|
|
101
|
+
// ponytail: a fixed number of rounds instead of real recursion — these
|
|
102
|
+
// includes never nest more than a couple of levels deep.
|
|
103
|
+
for (let round = 0; round < 4; round++) {
|
|
104
|
+
let changed = false;
|
|
105
|
+
|
|
106
|
+
for (const [name, macro] of this.macros) {
|
|
107
|
+
const start = result.indexOf(`${name}(`);
|
|
108
|
+
if (start < 0) continue;
|
|
109
|
+
|
|
110
|
+
const args = this.readArgs(result, start + name.length);
|
|
111
|
+
if (!args) continue;
|
|
112
|
+
|
|
113
|
+
let body = macro.body;
|
|
114
|
+
macro.params.forEach((param, i) => {
|
|
115
|
+
body = body.split(param).join(args.values[i] ?? '');
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
result = result.slice(0, start) + body + result.slice(args.end);
|
|
119
|
+
changed = true;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (!changed) break;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return result;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Reads a balanced `(a, b)` starting at `open`, splitting on top-level commas. */
|
|
129
|
+
private readArgs(text: string, open: number): { values: string[]; end: number } | null {
|
|
130
|
+
if (text[open] !== '(') return null;
|
|
131
|
+
|
|
132
|
+
const values: string[] = [];
|
|
133
|
+
let current = '';
|
|
134
|
+
let depth = 0;
|
|
135
|
+
|
|
136
|
+
for (let i = open; i < text.length; i++) {
|
|
137
|
+
const char = text[i];
|
|
138
|
+
|
|
139
|
+
if (char === '(') {
|
|
140
|
+
depth++;
|
|
141
|
+
if (depth === 1) continue;
|
|
142
|
+
} else if (char === ')') {
|
|
143
|
+
depth--;
|
|
144
|
+
if (depth === 0) {
|
|
145
|
+
values.push(current.trim());
|
|
146
|
+
return { values, end: i + 1 };
|
|
147
|
+
}
|
|
148
|
+
} else if (char === ',' && depth === 1) {
|
|
149
|
+
values.push(current.trim());
|
|
150
|
+
current = '';
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
current += char;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
parse(): ParsedInclude {
|
|
161
|
+
const result: ParsedInclude = {
|
|
162
|
+
natives: [],
|
|
163
|
+
forwards: [],
|
|
164
|
+
constants: [],
|
|
165
|
+
enums: [],
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
let currentDocs: string | undefined;
|
|
169
|
+
|
|
170
|
+
for (let i = 0; i < this.lines.length; i++) {
|
|
171
|
+
const line = this.lines[i].trim();
|
|
172
|
+
|
|
173
|
+
// Extract documentation
|
|
174
|
+
if (line.startsWith('/**')) {
|
|
175
|
+
currentDocs = this.extractDocs(i);
|
|
176
|
+
// Skip to end of comment
|
|
177
|
+
while (i < this.lines.length && !this.lines[i].includes('*/')) {
|
|
178
|
+
i++;
|
|
179
|
+
}
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (line.startsWith('native ')) {
|
|
184
|
+
const native = this.parseNative(line, currentDocs);
|
|
185
|
+
if (native) result.natives.push(native);
|
|
186
|
+
currentDocs = undefined;
|
|
187
|
+
} else if (line.startsWith('forward ')) {
|
|
188
|
+
const forward = this.parseForward(line, currentDocs);
|
|
189
|
+
if (forward) result.forwards.push(forward);
|
|
190
|
+
currentDocs = undefined;
|
|
191
|
+
} else if (/^#define\s/.test(line)) {
|
|
192
|
+
const constant = this.parseDefine(line, currentDocs);
|
|
193
|
+
if (constant) result.constants.push(constant);
|
|
194
|
+
currentDocs = undefined;
|
|
195
|
+
} else if (/^enum\b/.test(line)) {
|
|
196
|
+
// Named and anonymous alike.
|
|
197
|
+
const enumDecl = this.parseEnum(i, currentDocs);
|
|
198
|
+
if (enumDecl && enumDecl.members.length > 0) {
|
|
199
|
+
result.enums.push(enumDecl);
|
|
200
|
+
i = Math.max(i, this.currentLine); // Skip parsed lines, never back
|
|
201
|
+
}
|
|
202
|
+
currentDocs = undefined;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return result;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
private extractDocs(startLine: number): string {
|
|
210
|
+
const docs: string[] = [];
|
|
211
|
+
let i = startLine;
|
|
212
|
+
|
|
213
|
+
while (i < this.lines.length) {
|
|
214
|
+
const line = this.lines[i].trim();
|
|
215
|
+
if (line.endsWith('*/')) {
|
|
216
|
+
// Include last line content before */
|
|
217
|
+
const content = line
|
|
218
|
+
.replace(/\*\/$/, '')
|
|
219
|
+
.replace(/^\*/, '')
|
|
220
|
+
.trim();
|
|
221
|
+
if (content) docs.push(content);
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const content = line
|
|
226
|
+
.replace(/^\/\*\*/, '')
|
|
227
|
+
.replace(/^\*/, '')
|
|
228
|
+
.trim();
|
|
229
|
+
|
|
230
|
+
if (content) docs.push(content);
|
|
231
|
+
i++;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return docs.join('\n');
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private parseNative(line: string, docs?: string): NativeFunction | null {
|
|
238
|
+
// native functionName(params) or native Type:functionName(params)
|
|
239
|
+
const match = line.match(/native\s+(?:(\w+):)?(\w+)\s*\((.*?)\)/);
|
|
240
|
+
if (!match) return null;
|
|
241
|
+
|
|
242
|
+
const [, returnType, name, paramsStr] = match;
|
|
243
|
+
const params = this.parseParameters(paramsStr);
|
|
244
|
+
|
|
245
|
+
return {
|
|
246
|
+
name,
|
|
247
|
+
params,
|
|
248
|
+
returnType: returnType || 'any',
|
|
249
|
+
docs,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
private parseForward(line: string, docs?: string): ForwardDeclaration | null {
|
|
254
|
+
// forward functionName(params)
|
|
255
|
+
const match = line.match(/forward\s+(\w+)\s*\((.*?)\)/);
|
|
256
|
+
if (!match) return null;
|
|
257
|
+
|
|
258
|
+
const [, name, paramsStr] = match;
|
|
259
|
+
const params = this.parseParameters(paramsStr);
|
|
260
|
+
|
|
261
|
+
return {
|
|
262
|
+
name,
|
|
263
|
+
params,
|
|
264
|
+
returnType: 'void',
|
|
265
|
+
docs,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
private parseParameters(paramsStr: string): Parameter[] {
|
|
270
|
+
if (!paramsStr.trim()) return [];
|
|
271
|
+
|
|
272
|
+
const params: Parameter[] = [];
|
|
273
|
+
const parts = this.splitParameters(paramsStr);
|
|
274
|
+
|
|
275
|
+
for (const part of parts) {
|
|
276
|
+
const param = this.parseParameter(part.trim());
|
|
277
|
+
if (param) params.push(param);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return params;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
private splitParameters(str: string): string[] {
|
|
284
|
+
const params: string[] = [];
|
|
285
|
+
let current = '';
|
|
286
|
+
let bracketDepth = 0;
|
|
287
|
+
let braceDepth = 0;
|
|
288
|
+
|
|
289
|
+
for (const char of str) {
|
|
290
|
+
if (char === '[') {
|
|
291
|
+
bracketDepth++;
|
|
292
|
+
} else if (char === ']') {
|
|
293
|
+
bracketDepth--;
|
|
294
|
+
} else if (char === '{') {
|
|
295
|
+
braceDepth++;
|
|
296
|
+
} else if (char === '}') {
|
|
297
|
+
braceDepth--;
|
|
298
|
+
} else if (char === ',' && bracketDepth === 0 && braceDepth === 0) {
|
|
299
|
+
if (current.trim()) {
|
|
300
|
+
params.push(current.trim());
|
|
301
|
+
}
|
|
302
|
+
current = '';
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
current += char;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (current.trim()) {
|
|
309
|
+
params.push(current.trim());
|
|
310
|
+
}
|
|
311
|
+
return params;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
private parseParameter(str: string): Parameter | null {
|
|
315
|
+
if (!str) return null;
|
|
316
|
+
|
|
317
|
+
let isConst = false;
|
|
318
|
+
let isRef = false;
|
|
319
|
+
let isArray = false;
|
|
320
|
+
let isRest = false;
|
|
321
|
+
let type = 'any';
|
|
322
|
+
let name = '';
|
|
323
|
+
let defaultValue: string | undefined;
|
|
324
|
+
let arraySize: string | undefined;
|
|
325
|
+
|
|
326
|
+
// Check for rest parameters (...)
|
|
327
|
+
if (str.includes('...')) {
|
|
328
|
+
isRest = true;
|
|
329
|
+
str = str.replace('...', '');
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Remove const
|
|
333
|
+
str = str.replace(/^const\s+/, () => {
|
|
334
|
+
isConst = true;
|
|
335
|
+
return '';
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
// Remove &
|
|
339
|
+
str = str.replace(/^&/, () => {
|
|
340
|
+
isRef = true;
|
|
341
|
+
return '';
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
// Extract default value (including array defaults like {255, 255, 250, 0})
|
|
345
|
+
const equals = str.indexOf('=');
|
|
346
|
+
if (equals > 0 && equals < str.length - 1) {
|
|
347
|
+
defaultValue = str.slice(equals + 1).trim();
|
|
348
|
+
str = str.slice(0, equals).trim();
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Extract array. Pawn allows more than one trailing dimension (e.g.
|
|
352
|
+
// sorting.inc's `array[][]`), so every bracket group is stripped, not
|
|
353
|
+
// just the last one — otherwise the leftover `[]` ends up in the name.
|
|
354
|
+
// A 2D array argument is not interchangeable with a 1D one at the call
|
|
355
|
+
// site (amxxpc rejects it with "array dimensions do not match"), so the
|
|
356
|
+
// count is kept, not just whether it is an array at all.
|
|
357
|
+
let dimensions = 0;
|
|
358
|
+
for (let group = str.match(/\[([^[\]]*)\]$/); group && group.index! > 0; group = str.match(/\[([^[\]]*)\]$/)) {
|
|
359
|
+
str = str.slice(0, group.index).trim();
|
|
360
|
+
arraySize = group[1] || arraySize;
|
|
361
|
+
isArray = true;
|
|
362
|
+
dimensions++;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Extract type
|
|
366
|
+
// Pawn allows a multi-tag: {Float,_}:value — take the first real tag,
|
|
367
|
+
// `_` stands for "any untagged".
|
|
368
|
+
const multiTagMatch = str.match(/^\{([^}]*)\}:(.+)$/);
|
|
369
|
+
const typeMatch = str.match(/^(\w+):(.+)$/);
|
|
370
|
+
|
|
371
|
+
if (multiTagMatch) {
|
|
372
|
+
const tags = multiTagMatch[1].split(',').map(t => t.trim()).filter(t => t && t !== '_');
|
|
373
|
+
type = tags[0] || 'any';
|
|
374
|
+
name = multiTagMatch[2].trim();
|
|
375
|
+
} else if (typeMatch) {
|
|
376
|
+
type = typeMatch[1];
|
|
377
|
+
name = typeMatch[2].trim();
|
|
378
|
+
} else {
|
|
379
|
+
name = str.trim();
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Handle rest parameters
|
|
383
|
+
if (isRest) {
|
|
384
|
+
name = 'args';
|
|
385
|
+
isArray = true;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return {
|
|
389
|
+
name,
|
|
390
|
+
type,
|
|
391
|
+
isArray,
|
|
392
|
+
isRef,
|
|
393
|
+
isConst,
|
|
394
|
+
defaultValue,
|
|
395
|
+
arraySize,
|
|
396
|
+
isRest,
|
|
397
|
+
dimensions: isArray ? dimensions : undefined,
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
private parseDefine(line: string, docs?: string): Constant | null {
|
|
402
|
+
const match = line.match(/#define\s+(\w+)\s+(.+)/);
|
|
403
|
+
if (!match) return null;
|
|
404
|
+
|
|
405
|
+
const [, name, value] = match;
|
|
406
|
+
return { name, value: this.expand(value.trim()), docs };
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
private parseEnum(startLine: number, docs?: string): EnumDeclaration | null {
|
|
410
|
+
const firstLine = this.lines[startLine].trim();
|
|
411
|
+
|
|
412
|
+
// "enum Name", "enum Name (<<= 1)", "enum" or "enum {".
|
|
413
|
+
const enumName = firstLine.match(/^enum\s+(\w+)/)?.[1];
|
|
414
|
+
// Without a clause Pawn counts `+= 1`; AMX Mod X's flag enums double, `(<<= 1)`.
|
|
415
|
+
const [, op = '+', by = '1'] = firstLine.match(/\((\+|\*|<<)=([^)]+)\)/) ?? [];
|
|
416
|
+
const step = ENUM_STEP[op];
|
|
417
|
+
const stepBy = evalInt(by);
|
|
418
|
+
|
|
419
|
+
// The opening brace: on the enum's own line or a later one.
|
|
420
|
+
let i = startLine;
|
|
421
|
+
while (i < this.lines.length && !this.lines[i].includes('{')) i++;
|
|
422
|
+
if (i >= this.lines.length) {
|
|
423
|
+
this.currentLine = startLine;
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const members: EnumMember[] = [];
|
|
428
|
+
let currentMemberDocs: string | undefined;
|
|
429
|
+
let lastValue: number | undefined = 0;
|
|
430
|
+
|
|
431
|
+
// Members follow the brace on its line too - all of them in a one-line
|
|
432
|
+
// enum, `enum E { A = 0, B, C };` - and end at the closing brace,
|
|
433
|
+
// wherever it is. A line that is only `};` is one case of that.
|
|
434
|
+
let text = this.lines[i].slice(this.lines[i].indexOf('{') + 1);
|
|
435
|
+
|
|
436
|
+
while (true) {
|
|
437
|
+
const line = text.trim();
|
|
438
|
+
|
|
439
|
+
if (line.startsWith('/**')) {
|
|
440
|
+
// A doc comment is the next member's.
|
|
441
|
+
currentMemberDocs = this.extractDocs(i);
|
|
442
|
+
while (i < this.lines.length && !this.lines[i].includes('*/')) i++;
|
|
443
|
+
} else if (line.startsWith('/*') && line.endsWith('*/')) {
|
|
444
|
+
currentMemberDocs = line.replace(/^\/\*/, '').replace(/\*\/$/, '').trim();
|
|
445
|
+
} else if (line.startsWith('/*') && !line.includes('*/')) {
|
|
446
|
+
while (i < this.lines.length && !this.lines[i].includes('*/')) i++;
|
|
447
|
+
} else {
|
|
448
|
+
const uncommented = line.replace(/\/\*.*?\*\//g, '').replace(/\/\/.*$/, '');
|
|
449
|
+
// A comment after a member that runs on to later lines - ns_const.inc's
|
|
450
|
+
// `NSGame_Unknown, /**< Can find the gameplay entity, but can't` - ends
|
|
451
|
+
// the line's code, and its lines are no members.
|
|
452
|
+
const open = uncommented.indexOf('/*');
|
|
453
|
+
const code = open < 0 ? uncommented : uncommented.slice(0, open);
|
|
454
|
+
const close = code.indexOf('}');
|
|
455
|
+
|
|
456
|
+
for (const part of splitTopLevel(close < 0 ? code : code.slice(0, close))) {
|
|
457
|
+
const member = this.parseEnumMember(part, currentMemberDocs, lastValue);
|
|
458
|
+
if (!member) continue;
|
|
459
|
+
members.push(member);
|
|
460
|
+
// An explicit value re-anchors the count. It is an expression as
|
|
461
|
+
// often as it is a literal — reapi opens every hookchain region
|
|
462
|
+
// with BEGIN_FUNC_REGION(gamedll), which expands to (1024 * 1) —
|
|
463
|
+
// and the members after it continue 1025, 1026... Counting from
|
|
464
|
+
// zero there made hook() register an unrelated hookchain.
|
|
465
|
+
if (member.value) lastValue = evalInt(member.value);
|
|
466
|
+
lastValue = lastValue === undefined || stepBy === undefined ? undefined : step(lastValue, stepBy);
|
|
467
|
+
currentMemberDocs = undefined;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (close >= 0) {
|
|
471
|
+
this.currentLine = i;
|
|
472
|
+
return { name: enumName, members, docs };
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
if (open >= 0) {
|
|
476
|
+
i++;
|
|
477
|
+
while (i < this.lines.length && !this.lines[i].includes('*/')) i++;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
i++;
|
|
482
|
+
if (i >= this.lines.length) break;
|
|
483
|
+
text = this.lines[i];
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// No closing brace before the end of the file: not an enum to read.
|
|
487
|
+
this.currentLine = startLine;
|
|
488
|
+
return null;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/** One member as splitTopLevel() cut it from a line without its comments: `NAME` or `NAME = value`. */
|
|
492
|
+
private parseEnumMember(part: string, docs?: string, autoValue?: number): EnumMember | null {
|
|
493
|
+
const match = part.match(/^(\w+)(?:\s*=\s*(.+))?/);
|
|
494
|
+
if (!match) return null;
|
|
495
|
+
|
|
496
|
+
const [, name, value] = match;
|
|
497
|
+
|
|
498
|
+
// Use provided value, or auto-increment value, or undefined
|
|
499
|
+
const explicit = value?.trim();
|
|
500
|
+
const finalValue = explicit
|
|
501
|
+
? this.expand(explicit)
|
|
502
|
+
: (autoValue !== undefined ? autoValue.toString() : undefined);
|
|
503
|
+
|
|
504
|
+
return { name, value: finalValue, docs };
|
|
505
|
+
}
|
|
506
|
+
}
|
package/src/system.mjs
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// Which system a server runs - Windows or Linux - and what that decides.
|
|
2
|
+
//
|
|
3
|
+
// A plugin's .aot is machine code in the target system's object format: wamrc
|
|
4
|
+
// writes COFF for Windows and ELF for Linux, and each system's loader knows
|
|
5
|
+
// only its own relocations. The code, the natives and the calls are the same;
|
|
6
|
+
// the file is not. So what a build compiles for is the server's system, not
|
|
7
|
+
// the one the build runs on: `--target-abi=msvc` or `gnu`, which either wamrc
|
|
8
|
+
// - Windows' or Linux' - produces byte for byte the same.
|
|
9
|
+
//
|
|
10
|
+
// The server's system is, first to last: `--os windows|linux`, AMXTS_SERVER_OS,
|
|
11
|
+
// what AMXTS_SERVER holds (hlds.exe or hlds_linux beside the game folder, else
|
|
12
|
+
// the modules' files), and this machine's own.
|
|
13
|
+
//
|
|
14
|
+
// Plain JavaScript: the build (scripts/system.ts) and the amxts command, through
|
|
15
|
+
// cli-api, both read it.
|
|
16
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
17
|
+
import { createRequire } from 'node:module';
|
|
18
|
+
import { dirname, join, resolve } from 'node:path';
|
|
19
|
+
import process from 'node:process';
|
|
20
|
+
import { fileURLToPath } from 'node:url';
|
|
21
|
+
|
|
22
|
+
const CORE = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
23
|
+
|
|
24
|
+
/** @typedef {'windows' | 'linux'} System */
|
|
25
|
+
|
|
26
|
+
/** @type {readonly System[]} */
|
|
27
|
+
export const SYSTEMS = ['windows', 'linux'];
|
|
28
|
+
|
|
29
|
+
/** The system this machine runs. @type {System} */
|
|
30
|
+
export const HOST_SYSTEM = process.platform === 'win32' ? 'windows' : 'linux';
|
|
31
|
+
|
|
32
|
+
/** How a person writes it. @type {Record<System, string>} */
|
|
33
|
+
export const SYSTEM_NAME = { windows: 'Windows', linux: 'Linux' };
|
|
34
|
+
|
|
35
|
+
/** wamrc's --target-abi: the object format the machine code is written in. @type {Record<System, string>} */
|
|
36
|
+
export const TARGET_ABI = { windows: 'msvc', linux: 'gnu' };
|
|
37
|
+
|
|
38
|
+
/** The amxts module's file, as AMX Mod X on that system looks it up for `amxts_amxx` in modules.ini. @type {Record<System, string>} */
|
|
39
|
+
export const MODULE_FILE = { windows: 'amxts_amxx.dll', linux: 'amxts_amxx_i386.so' };
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* `windows`, `win32`, `linux`, any case; null for anything else.
|
|
43
|
+
* @param {string | undefined | null} value
|
|
44
|
+
* @returns {System | null} the system, or null
|
|
45
|
+
*/
|
|
46
|
+
export function parseSystem(value) {
|
|
47
|
+
const text = (value ?? '').trim().toLowerCase();
|
|
48
|
+
if (text === 'windows' || text === 'win32' || text === 'win') return 'windows';
|
|
49
|
+
if (text === 'linux') return 'linux';
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* What a server's files say it runs. `amxtsDir` is AMXTS_SERVER: the server's
|
|
55
|
+
* addons/amxts, so hlds sits three folders up. Null when nothing there says.
|
|
56
|
+
* @param {string} amxtsDir
|
|
57
|
+
* @returns {{ system: System, reason: string } | null} the system and the file that said so, or null
|
|
58
|
+
*/
|
|
59
|
+
export function detectServerSystem(amxtsDir) {
|
|
60
|
+
if (!amxtsDir) return null;
|
|
61
|
+
const gameDir = resolve(amxtsDir, '..', '..');
|
|
62
|
+
const hldsDir = resolve(gameDir, '..');
|
|
63
|
+
if (existsSync(join(hldsDir, 'hlds_linux'))) return { system: 'linux', reason: 'hlds_linux' };
|
|
64
|
+
if (existsSync(join(hldsDir, 'hlds.exe'))) return { system: 'windows', reason: 'hlds.exe' };
|
|
65
|
+
|
|
66
|
+
// A server reached over a share may have only its game folder there: the
|
|
67
|
+
// modules say which system they were built for.
|
|
68
|
+
for (const dir of [join(gameDir, 'addons', 'amxmodx', 'modules'), join(gameDir, 'addons', 'amxmodx', 'dlls')]) {
|
|
69
|
+
const files = existsSync(dir) ? readdirSync(dir) : [];
|
|
70
|
+
const so = files.find(file => file.endsWith('.so'));
|
|
71
|
+
const dll = files.find(file => file.toLowerCase().endsWith('.dll'));
|
|
72
|
+
if (so && !dll) return { system: 'linux', reason: so };
|
|
73
|
+
if (dll && !so) return { system: 'windows', reason: dll };
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @typedef {object} ServerSystem
|
|
80
|
+
* @property {System} system Windows or Linux
|
|
81
|
+
* @property {'flag' | 'env' | 'server' | 'host'} from how it was decided
|
|
82
|
+
* @property {string} [reason] what in the server's folder said so, when that decided it
|
|
83
|
+
*/
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* The system a build compiles for; see the top of this file.
|
|
87
|
+
* @param {string[]} [argv]
|
|
88
|
+
* @param {Record<string, string | undefined>} [env]
|
|
89
|
+
* @returns {ServerSystem} the system and how it was decided
|
|
90
|
+
*/
|
|
91
|
+
export function serverSystem(argv = process.argv, env = process.env) {
|
|
92
|
+
const at = argv.findIndex(arg => arg === '--os' || arg.startsWith('--os='));
|
|
93
|
+
if (at >= 0) {
|
|
94
|
+
const value = argv[at].includes('=') ? argv[at].slice(argv[at].indexOf('=') + 1) : argv[at + 1];
|
|
95
|
+
const system = parseSystem(value);
|
|
96
|
+
if (!system) throw new Error(`--os ${value ?? ''}: windows or linux`);
|
|
97
|
+
return { system, from: 'flag' };
|
|
98
|
+
}
|
|
99
|
+
if (env.AMXTS_SERVER_OS) {
|
|
100
|
+
const system = parseSystem(env.AMXTS_SERVER_OS);
|
|
101
|
+
if (!system) throw new Error(`AMXTS_SERVER_OS=${env.AMXTS_SERVER_OS}: windows or linux`);
|
|
102
|
+
return { system, from: 'env' };
|
|
103
|
+
}
|
|
104
|
+
const found = detectServerSystem(env.AMXTS_SERVER ?? '');
|
|
105
|
+
if (found) return { system: found.system, from: 'server', reason: found.reason };
|
|
106
|
+
return { system: HOST_SYSTEM, from: 'host' };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The server's system as the build reports it: "Linux (hlds_linux)".
|
|
111
|
+
* @param {ServerSystem} found
|
|
112
|
+
*/
|
|
113
|
+
export function describeSystem(found) {
|
|
114
|
+
const why = found.from === 'flag' ? '--os' : found.from === 'env' ? 'AMXTS_SERVER_OS' : found.from === 'server' ? found.reason : 'this machine';
|
|
115
|
+
return `${SYSTEM_NAME[found.system]} (${why})`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* An executable's file name on that system.
|
|
120
|
+
* @param {string} name
|
|
121
|
+
* @param {System} [system]
|
|
122
|
+
*/
|
|
123
|
+
export function executable(name, system = HOST_SYSTEM) {
|
|
124
|
+
return system === 'windows' ? `${name}.exe` : name;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** The package that carries wamrc for this machine: the core's optional dependency for its system. */
|
|
128
|
+
export const WAMRC_PACKAGE = `@amxts/wamrc-${process.platform}-${process.arch}`;
|
|
129
|
+
|
|
130
|
+
/** Where that package would put wamrc, whether or not it is installed; null when it resolves nowhere. */
|
|
131
|
+
function packagedWamrc() {
|
|
132
|
+
try {
|
|
133
|
+
return join(dirname(createRequire(import.meta.url).resolve(`${WAMRC_PACKAGE}/package.json`)), executable('wamrc'));
|
|
134
|
+
} catch {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* wamrc as the core has it for this machine: AMXTS_WAMRC, else the one of
|
|
141
|
+
* its package for this system (an installed core), else the one built in
|
|
142
|
+
* runtime/deps/wamr (a multi-config build puts it in Release/, a Makefile
|
|
143
|
+
* build beside it), else the one `bun run build:linux` made in
|
|
144
|
+
* runtime/build/linux. Either system's wamrc compiles for either system.
|
|
145
|
+
* A checkout links the package's folder, which has no wamrc of its own.
|
|
146
|
+
* @param {Record<string, string | undefined>} [env]
|
|
147
|
+
* @returns {string} its path, which may not exist
|
|
148
|
+
*/
|
|
149
|
+
export function wamrcPath(env = process.env) {
|
|
150
|
+
if (env.AMXTS_WAMRC) return env.AMXTS_WAMRC;
|
|
151
|
+
const name = executable('wamrc');
|
|
152
|
+
const build = join(CORE, 'runtime/deps/wamr/wamr-compiler/build');
|
|
153
|
+
const candidates = [packagedWamrc(), join(build, 'Release', name), join(build, name), ...(HOST_SYSTEM === 'linux' ? [join(CORE, 'runtime/build/linux', name)] : [])].filter(file => file !== null);
|
|
154
|
+
return candidates.find(file => existsSync(file)) ?? candidates[0];
|
|
155
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// What the testing library compiled, kept on disk between test runs
|
|
2
|
+
// (scripts/compile-cache.ts): a second run takes a compile again only while
|
|
3
|
+
// every file it read is the same.
|
|
4
|
+
//
|
|
5
|
+
// The cache is node_modules/.cache/amxts in the folder the tests run from.
|
|
6
|
+
// AMXTS_TEST_CACHE=0 turns it off; AMXTS_TEST_CACHE=<folder> moves it.
|
|
7
|
+
import { dirname, join, resolve } from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
import { codeIdentity, diskCache } from '../../scripts/compile-cache';
|
|
10
|
+
|
|
11
|
+
const setting = process.env.AMXTS_TEST_CACHE;
|
|
12
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
|
|
14
|
+
const cache = diskCache(
|
|
15
|
+
setting === '0' ? null : resolve(setting || 'node_modules/.cache/amxts', 'compile'),
|
|
16
|
+
() => codeIdentity([join(HERE, 'compile.ts'), join(HERE, 'compile-cache.ts')]),
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
/** Whether results are kept on disk: not with AMXTS_TEST_CACHE=0. */
|
|
20
|
+
export const cacheOn = cache.on;
|
|
21
|
+
|
|
22
|
+
/** How often this process took a result from the disk, and made one. */
|
|
23
|
+
export const cacheCounts = cache.counts;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* `run`'s value, from the disk when an earlier run made it from the same
|
|
27
|
+
* sources, or made now and kept. `parts` is what it depends on besides the
|
|
28
|
+
* files it reads: the entry, the flags. `keep` says whether a failure is
|
|
29
|
+
* worth keeping - a compile error is, a file that could not be opened is not.
|
|
30
|
+
*/
|
|
31
|
+
export const cached = cache.cached;
|