@rhost/testkit 0.1.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +393 -5
- package/ROADMAP.md +241 -0
- package/dist/benchmark.d.ts +44 -0
- package/dist/benchmark.d.ts.map +1 -0
- package/dist/benchmark.js +118 -0
- package/dist/benchmark.js.map +1 -0
- package/dist/cli/deploy.d.ts +2 -0
- package/dist/cli/deploy.d.ts.map +1 -0
- package/dist/cli/deploy.js +120 -0
- package/dist/cli/deploy.js.map +1 -0
- package/dist/cli/fmt.d.ts +2 -0
- package/dist/cli/fmt.d.ts.map +1 -0
- package/dist/cli/fmt.js +119 -0
- package/dist/cli/fmt.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +81 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +2 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +210 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/validate.d.ts +2 -0
- package/dist/cli/validate.d.ts.map +1 -0
- package/dist/cli/validate.js +126 -0
- package/dist/cli/validate.js.map +1 -0
- package/dist/cli/watch.d.ts +2 -0
- package/dist/cli/watch.d.ts.map +1 -0
- package/dist/cli/watch.js +136 -0
- package/dist/cli/watch.js.map +1 -0
- package/dist/client.d.ts +48 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +113 -30
- package/dist/client.js.map +1 -1
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +1 -1
- package/dist/container.js.map +1 -1
- package/dist/deployer.d.ts +86 -0
- package/dist/deployer.d.ts.map +1 -0
- package/dist/deployer.js +154 -0
- package/dist/deployer.js.map +1 -0
- package/dist/expect.d.ts +27 -1
- package/dist/expect.d.ts.map +1 -1
- package/dist/expect.js +47 -2
- package/dist/expect.js.map +1 -1
- package/dist/index.d.ts +10 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +39 -1
- package/dist/index.js.map +1 -1
- package/dist/preflight.d.ts +70 -0
- package/dist/preflight.d.ts.map +1 -0
- package/dist/preflight.js +121 -0
- package/dist/preflight.js.map +1 -0
- package/dist/reporter.d.ts +2 -0
- package/dist/reporter.d.ts.map +1 -1
- package/dist/reporter.js +24 -1
- package/dist/reporter.js.map +1 -1
- package/dist/runner.d.ts +83 -2
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +137 -8
- package/dist/runner.js.map +1 -1
- package/dist/snapshots.d.ts +84 -0
- package/dist/snapshots.d.ts.map +1 -0
- package/dist/snapshots.js +230 -0
- package/dist/snapshots.js.map +1 -0
- package/dist/validator/builtins.d.ts +18 -0
- package/dist/validator/builtins.d.ts.map +1 -0
- package/dist/validator/builtins.js +265 -0
- package/dist/validator/builtins.js.map +1 -0
- package/dist/validator/checker.d.ts +13 -0
- package/dist/validator/checker.d.ts.map +1 -0
- package/dist/validator/checker.js +111 -0
- package/dist/validator/checker.js.map +1 -0
- package/dist/validator/clobber.d.ts +7 -0
- package/dist/validator/clobber.d.ts.map +1 -0
- package/dist/validator/clobber.js +102 -0
- package/dist/validator/clobber.js.map +1 -0
- package/dist/validator/compat.d.ts +19 -0
- package/dist/validator/compat.d.ts.map +1 -0
- package/dist/validator/compat.js +58 -0
- package/dist/validator/compat.js.map +1 -0
- package/dist/validator/formatter.d.ts +21 -0
- package/dist/validator/formatter.d.ts.map +1 -0
- package/dist/validator/formatter.js +120 -0
- package/dist/validator/formatter.js.map +1 -0
- package/dist/validator/index.d.ts +57 -0
- package/dist/validator/index.d.ts.map +1 -0
- package/dist/validator/index.js +133 -0
- package/dist/validator/index.js.map +1 -0
- package/dist/validator/parser.d.ts +16 -0
- package/dist/validator/parser.d.ts.map +1 -0
- package/dist/validator/parser.js +260 -0
- package/dist/validator/parser.js.map +1 -0
- package/dist/validator/tokenizer.d.ts +28 -0
- package/dist/validator/tokenizer.d.ts.map +1 -0
- package/dist/validator/tokenizer.js +174 -0
- package/dist/validator/tokenizer.js.map +1 -0
- package/dist/validator/types.d.ts +55 -0
- package/dist/validator/types.d.ts.map +1 -0
- package/dist/validator/types.js +6 -0
- package/dist/validator/types.js.map +1 -0
- package/dist/watcher.d.ts +44 -0
- package/dist/watcher.d.ts.map +1 -0
- package/dist/watcher.js +297 -0
- package/dist/watcher.js.map +1 -0
- package/dist/world.d.ts +79 -0
- package/dist/world.d.ts.map +1 -1
- package/dist/world.js +167 -1
- package/dist/world.js.map +1 -1
- package/package.json +19 -3
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// RhostMUSH softcode tokenizer
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.tokenize = tokenize;
|
|
7
|
+
// Characters that end a plain-text accumulation run.
|
|
8
|
+
// These must be checked before starting a new TEXT run.
|
|
9
|
+
const STRUCTURAL_RE = /[\\%\[\]()\,,a-zA-Z_]/;
|
|
10
|
+
function isIdentStart(ch) {
|
|
11
|
+
const c = ch.charCodeAt(0);
|
|
12
|
+
return (c >= 65 && c <= 90) || (c >= 97 && c <= 122) || c === 95; // A-Z, a-z, _
|
|
13
|
+
}
|
|
14
|
+
function isIdentChar(ch) {
|
|
15
|
+
const c = ch.charCodeAt(0);
|
|
16
|
+
return ((c >= 65 && c <= 90) ||
|
|
17
|
+
(c >= 97 && c <= 122) ||
|
|
18
|
+
(c >= 48 && c <= 57) ||
|
|
19
|
+
c === 95); // A-Z, a-z, 0-9, _
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Single-character percent substitutions recognised by RhostMUSH.
|
|
23
|
+
* Anything else after % is treated as a literal %, not a substitution.
|
|
24
|
+
*/
|
|
25
|
+
const SINGLE_CHAR_SUBST = new Set([
|
|
26
|
+
'#', 'N', 'n', 'L', 'l', 'P', 'p', 'T', 't', 'B', 'b',
|
|
27
|
+
'R', 'r', 'A', 'a', 'O', 'o', 'S', 's', 'X', 'x', '+',
|
|
28
|
+
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
|
29
|
+
'C', 'c', // ANSI carry
|
|
30
|
+
'v', 'V', // attribute value
|
|
31
|
+
'w', 'W', // attribute name
|
|
32
|
+
'u', 'U', // room name
|
|
33
|
+
'f', 'F', // from
|
|
34
|
+
'k', 'K', // money
|
|
35
|
+
'm', 'M', // last entered command
|
|
36
|
+
]);
|
|
37
|
+
/**
|
|
38
|
+
* Tokenize a RhostMUSH softcode expression into a flat token stream.
|
|
39
|
+
*
|
|
40
|
+
* Rules (in priority order):
|
|
41
|
+
* 1. `\X` → ESC(X) — escape always wins
|
|
42
|
+
* 2. `%%` → TEXT('%') — literal percent
|
|
43
|
+
* 3. `%qX` / `%iX` → SUBST('%qX') — 3-char register subst
|
|
44
|
+
* 4. `%X` (known) → SUBST('%X') — 2-char substitution
|
|
45
|
+
* 5. `%` (unknown) → TEXT('%') — treat as literal
|
|
46
|
+
* 6. `[` → LBRACKET
|
|
47
|
+
* 7. `]` → RBRACKET
|
|
48
|
+
* 8. `)` → RPAREN
|
|
49
|
+
* 9. `,` → COMMA
|
|
50
|
+
* 10. `word(` → FNAME(word) + LPAREN('(')
|
|
51
|
+
* 11. `word` → TEXT(word) — identifier not before (
|
|
52
|
+
* 12. `(` → TEXT('(') — ( not after identifier
|
|
53
|
+
* 13. <run> → TEXT(run) — anything else
|
|
54
|
+
*/
|
|
55
|
+
function tokenize(input) {
|
|
56
|
+
const tokens = [];
|
|
57
|
+
let pos = 0;
|
|
58
|
+
const len = input.length;
|
|
59
|
+
while (pos < len) {
|
|
60
|
+
const ch = input[pos];
|
|
61
|
+
// ---- 1. Backslash escape ----
|
|
62
|
+
if (ch === '\\') {
|
|
63
|
+
if (pos + 1 < len) {
|
|
64
|
+
tokens.push({ type: 'ESC', value: input[pos + 1], offset: pos });
|
|
65
|
+
pos += 2;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
// Trailing backslash: literal backslash
|
|
69
|
+
tokens.push({ type: 'TEXT', value: '\\', offset: pos });
|
|
70
|
+
pos++;
|
|
71
|
+
}
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
// ---- 2–5. Percent substitutions ----
|
|
75
|
+
if (ch === '%') {
|
|
76
|
+
if (pos + 1 >= len) {
|
|
77
|
+
tokens.push({ type: 'TEXT', value: '%', offset: pos });
|
|
78
|
+
pos++;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const next = input[pos + 1];
|
|
82
|
+
// %% → literal %
|
|
83
|
+
if (next === '%') {
|
|
84
|
+
tokens.push({ type: 'TEXT', value: '%', offset: pos });
|
|
85
|
+
pos += 2;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
// %q0–%q9, %qA–%qZ (q-register), %i0–%i9 (iter var) → 3-char subst
|
|
89
|
+
if ((next === 'q' || next === 'Q' || next === 'i' || next === 'I') &&
|
|
90
|
+
pos + 2 < len && /[0-9a-zA-Z]/.test(input[pos + 2])) {
|
|
91
|
+
tokens.push({ type: 'SUBST', value: input.slice(pos, pos + 3), offset: pos });
|
|
92
|
+
pos += 3;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
// Single-char known substitutions
|
|
96
|
+
if (SINGLE_CHAR_SUBST.has(next)) {
|
|
97
|
+
tokens.push({ type: 'SUBST', value: input.slice(pos, pos + 2), offset: pos });
|
|
98
|
+
pos += 2;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
// Unknown %X: literal %
|
|
102
|
+
tokens.push({ type: 'TEXT', value: '%', offset: pos });
|
|
103
|
+
pos++;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
// ---- 6–9. Single structural characters ----
|
|
107
|
+
if (ch === '[') {
|
|
108
|
+
tokens.push({ type: 'LBRACKET', value: '[', offset: pos });
|
|
109
|
+
pos++;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (ch === ']') {
|
|
113
|
+
tokens.push({ type: 'RBRACKET', value: ']', offset: pos });
|
|
114
|
+
pos++;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (ch === ')') {
|
|
118
|
+
tokens.push({ type: 'RPAREN', value: ')', offset: pos });
|
|
119
|
+
pos++;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (ch === ',') {
|
|
123
|
+
tokens.push({ type: 'COMMA', value: ',', offset: pos });
|
|
124
|
+
pos++;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
// ---- 10–11. Identifier: FNAME+LPAREN or plain TEXT ----
|
|
128
|
+
if (isIdentStart(ch)) {
|
|
129
|
+
const start = pos;
|
|
130
|
+
while (pos < len && isIdentChar(input[pos])) {
|
|
131
|
+
pos++;
|
|
132
|
+
}
|
|
133
|
+
const word = input.slice(start, pos);
|
|
134
|
+
if (pos < len && input[pos] === '(') {
|
|
135
|
+
// Function call: emit FNAME then LPAREN
|
|
136
|
+
tokens.push({ type: 'FNAME', value: word, offset: start });
|
|
137
|
+
tokens.push({ type: 'LPAREN', value: '(', offset: pos });
|
|
138
|
+
pos++;
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
// Bare identifier — text
|
|
142
|
+
tokens.push({ type: 'TEXT', value: word, offset: start });
|
|
143
|
+
}
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
// ---- 12. '(' not after an identifier: literal ----
|
|
147
|
+
if (ch === '(') {
|
|
148
|
+
tokens.push({ type: 'TEXT', value: '(', offset: pos });
|
|
149
|
+
pos++;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
// ---- 13. Plain text accumulation ----
|
|
153
|
+
{
|
|
154
|
+
const start = pos;
|
|
155
|
+
while (pos < len) {
|
|
156
|
+
const c = input[pos];
|
|
157
|
+
// Stop at any character that starts a higher-priority rule
|
|
158
|
+
if (c === '\\' || c === '%' ||
|
|
159
|
+
c === '[' || c === ']' ||
|
|
160
|
+
c === '(' || c === ')' ||
|
|
161
|
+
c === ',' ||
|
|
162
|
+
isIdentStart(c)) {
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
pos++;
|
|
166
|
+
}
|
|
167
|
+
if (pos > start) {
|
|
168
|
+
tokens.push({ type: 'TEXT', value: input.slice(start, pos), offset: start });
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return tokens;
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=tokenizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokenizer.js","sourceRoot":"","sources":["../../src/validator/tokenizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export type Severity = 'error' | 'warning';
|
|
2
|
+
/** A single diagnostic produced by the validator. */
|
|
3
|
+
export interface Diagnostic {
|
|
4
|
+
severity: Severity;
|
|
5
|
+
/** Error/warning code, e.g. 'E001', 'W002' */
|
|
6
|
+
code: string;
|
|
7
|
+
message: string;
|
|
8
|
+
/** Character offset in the original expression string */
|
|
9
|
+
offset: number;
|
|
10
|
+
/** Span length in characters (0 = point diagnostic) */
|
|
11
|
+
length: number;
|
|
12
|
+
}
|
|
13
|
+
/** Result returned by `validate()` */
|
|
14
|
+
export interface ValidationResult {
|
|
15
|
+
/** false if any diagnostic has severity 'error' */
|
|
16
|
+
valid: boolean;
|
|
17
|
+
diagnostics: Diagnostic[];
|
|
18
|
+
}
|
|
19
|
+
export type ASTNode = FunctionCallNode | BracketEvalNode | SubstitutionNode | RawTextNode;
|
|
20
|
+
/** A function call: `name(arg1, arg2, ...)` */
|
|
21
|
+
export interface FunctionCallNode {
|
|
22
|
+
type: 'FunctionCall';
|
|
23
|
+
/** Original casing preserved from source */
|
|
24
|
+
name: string;
|
|
25
|
+
/** Offset of the first character of the name */
|
|
26
|
+
nameOffset: number;
|
|
27
|
+
/**
|
|
28
|
+
* Each element is the list of nodes forming one argument.
|
|
29
|
+
* An empty inner array means an empty/missing argument.
|
|
30
|
+
*/
|
|
31
|
+
args: ASTNode[][];
|
|
32
|
+
/** Offset of the opening parenthesis */
|
|
33
|
+
offset: number;
|
|
34
|
+
}
|
|
35
|
+
/** An inline evaluation: `[expression]` */
|
|
36
|
+
export interface BracketEvalNode {
|
|
37
|
+
type: 'BracketEval';
|
|
38
|
+
nodes: ASTNode[];
|
|
39
|
+
/** Offset of the '[' */
|
|
40
|
+
offset: number;
|
|
41
|
+
}
|
|
42
|
+
/** A percent-substitution: `%#`, `%N`, `%q0`, `%0`–`%9`, `%%`, etc. */
|
|
43
|
+
export interface SubstitutionNode {
|
|
44
|
+
type: 'Substitution';
|
|
45
|
+
/** The raw substitution text as it appears in the source */
|
|
46
|
+
raw: string;
|
|
47
|
+
offset: number;
|
|
48
|
+
}
|
|
49
|
+
/** Literal text or an escaped character that requires no further analysis */
|
|
50
|
+
export interface RawTextNode {
|
|
51
|
+
type: 'RawText';
|
|
52
|
+
value: string;
|
|
53
|
+
offset: number;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/validator/types.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AAE3C,qDAAqD;AACrD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,QAAQ,CAAC;IACnB,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,MAAM,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,sCAAsC;AACtC,MAAM,WAAW,gBAAgB;IAC/B,mDAAmD;IACnD,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B;AAMD,MAAM,MAAM,OAAO,GACf,gBAAgB,GAChB,eAAe,GACf,gBAAgB,GAChB,WAAW,CAAC;AAEhB,+CAA+C;AAC/C,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,cAAc,CAAC;IACrB,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC;IAClB,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,2CAA2C;AAC3C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,wBAAwB;IACxB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,uEAAuE;AACvE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,cAAc,CAAC;IACrB,4DAA4D;IAC5D,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,6EAA6E;AAC7E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// Shared types for the RhostMUSH softcode validator
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/validator/types.ts"],"names":[],"mappings":";AAAA,8EAA8E;AAC9E,oDAAoD;AACpD,8EAA8E"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export interface WatchOptions {
|
|
2
|
+
/** Absolute paths of test files to watch and run */
|
|
3
|
+
files: string[];
|
|
4
|
+
/** Debounce delay in ms before re-running after a change. Default: 300 */
|
|
5
|
+
debounceMs?: number;
|
|
6
|
+
/** Clear terminal between runs. Default: true */
|
|
7
|
+
clearScreen?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare class RhostWatcher {
|
|
10
|
+
private readonly options;
|
|
11
|
+
private readonly debounceMs;
|
|
12
|
+
private readonly clearScreen;
|
|
13
|
+
private watcher;
|
|
14
|
+
private debounceTimer;
|
|
15
|
+
private pendingFiles;
|
|
16
|
+
private currentProcess;
|
|
17
|
+
private stopped;
|
|
18
|
+
private runCount;
|
|
19
|
+
constructor(options: WatchOptions);
|
|
20
|
+
/**
|
|
21
|
+
* Start watching. Runs an initial pass immediately, then re-runs on change.
|
|
22
|
+
* Blocks until `stop()` is called (or SIGINT).
|
|
23
|
+
*/
|
|
24
|
+
start(): Promise<void>;
|
|
25
|
+
/** Graceful shutdown: cancel pending timers, close watcher, kill child. */
|
|
26
|
+
stop(): Promise<void>;
|
|
27
|
+
private setupWatcher;
|
|
28
|
+
private runFiles;
|
|
29
|
+
private spawnFile;
|
|
30
|
+
private printBanner;
|
|
31
|
+
private printRunHeader;
|
|
32
|
+
/**
|
|
33
|
+
* Find the longest common directory path shared by all given dirs.
|
|
34
|
+
* Falls back to '/' (or drive root on Windows) if nothing in common.
|
|
35
|
+
*/
|
|
36
|
+
private commonRoot;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Recursively walk `rootDir` and return all test files matching
|
|
40
|
+
* `*.test.ts`, `*.test.js`, `*.spec.ts`, `*.spec.js`.
|
|
41
|
+
* Skips `node_modules`, `dist`, `.git`, `.next`, `.turbo`.
|
|
42
|
+
*/
|
|
43
|
+
export declare function discoverTestFiles(rootDir: string): string[];
|
|
44
|
+
//# sourceMappingURL=watcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../src/watcher.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,YAAY;IAC3B,oDAAoD;IACpD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAMD,qBAAa,YAAY;IAWX,OAAO,CAAC,QAAQ,CAAC,OAAO;IAVpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAU;IAEtC,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,YAAY,CAA0B;IAC9C,OAAO,CAAC,cAAc,CAA6B;IACnD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAK;gBAEQ,OAAO,EAAE,YAAY;IAKlD;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA+B5B,2EAA2E;IACrE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA2B3B,OAAO,CAAC,YAAY;YA2CN,QAAQ;IAuBtB,OAAO,CAAC,SAAS;IAyCjB,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,cAAc;IAqBtB;;;OAGG;IACH,OAAO,CAAC,UAAU;CAoBnB;AAMD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAI3D"}
|
package/dist/watcher.js
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// RhostWatcher — file-watch driven test re-runner
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.RhostWatcher = void 0;
|
|
40
|
+
exports.discoverTestFiles = discoverTestFiles;
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const child_process_1 = require("child_process");
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// RhostWatcher class
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
class RhostWatcher {
|
|
48
|
+
constructor(options) {
|
|
49
|
+
this.options = options;
|
|
50
|
+
this.watcher = null;
|
|
51
|
+
this.debounceTimer = null;
|
|
52
|
+
this.pendingFiles = new Set();
|
|
53
|
+
this.currentProcess = null;
|
|
54
|
+
this.stopped = false;
|
|
55
|
+
this.runCount = 0;
|
|
56
|
+
this.debounceMs = options.debounceMs ?? 300;
|
|
57
|
+
this.clearScreen = options.clearScreen !== false;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Start watching. Runs an initial pass immediately, then re-runs on change.
|
|
61
|
+
* Blocks until `stop()` is called (or SIGINT).
|
|
62
|
+
*/
|
|
63
|
+
async start() {
|
|
64
|
+
const files = this.options.files;
|
|
65
|
+
if (files.length === 0) {
|
|
66
|
+
console.error('rhost-testkit: No test files to watch.');
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
this.printBanner(files);
|
|
70
|
+
// Initial run
|
|
71
|
+
await this.runFiles(files, 'initial');
|
|
72
|
+
if (this.stopped)
|
|
73
|
+
return;
|
|
74
|
+
// Set up filesystem watching
|
|
75
|
+
const watchRoot = this.commonRoot(files.map((f) => path.dirname(f)));
|
|
76
|
+
this.setupWatcher(watchRoot, new Set(files.map((f) => path.resolve(f))));
|
|
77
|
+
// Block until stopped
|
|
78
|
+
await new Promise((resolve) => {
|
|
79
|
+
const poll = setInterval(() => {
|
|
80
|
+
if (this.stopped) {
|
|
81
|
+
clearInterval(poll);
|
|
82
|
+
resolve();
|
|
83
|
+
}
|
|
84
|
+
}, 100);
|
|
85
|
+
// Ensure this timer doesn't prevent Node from exiting naturally
|
|
86
|
+
if (typeof poll.unref === 'function')
|
|
87
|
+
poll.unref();
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/** Graceful shutdown: cancel pending timers, close watcher, kill child. */
|
|
91
|
+
async stop() {
|
|
92
|
+
this.stopped = true;
|
|
93
|
+
if (this.debounceTimer) {
|
|
94
|
+
clearTimeout(this.debounceTimer);
|
|
95
|
+
this.debounceTimer = null;
|
|
96
|
+
}
|
|
97
|
+
if (this.watcher) {
|
|
98
|
+
this.watcher.close();
|
|
99
|
+
this.watcher = null;
|
|
100
|
+
}
|
|
101
|
+
if (this.currentProcess) {
|
|
102
|
+
try {
|
|
103
|
+
this.currentProcess.kill('SIGTERM');
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// already exited
|
|
107
|
+
}
|
|
108
|
+
this.currentProcess = null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// -------------------------------------------------------------------------
|
|
112
|
+
// Internal: filesystem watcher setup
|
|
113
|
+
// -------------------------------------------------------------------------
|
|
114
|
+
setupWatcher(watchRoot, testFileSet) {
|
|
115
|
+
try {
|
|
116
|
+
this.watcher = fs.watch(watchRoot, { recursive: true }, (event, filename) => {
|
|
117
|
+
if (!filename || this.stopped)
|
|
118
|
+
return;
|
|
119
|
+
const resolved = path.isAbsolute(filename)
|
|
120
|
+
? filename
|
|
121
|
+
: path.resolve(watchRoot, filename);
|
|
122
|
+
if (!testFileSet.has(resolved))
|
|
123
|
+
return;
|
|
124
|
+
this.pendingFiles.add(resolved);
|
|
125
|
+
if (this.debounceTimer)
|
|
126
|
+
clearTimeout(this.debounceTimer);
|
|
127
|
+
this.debounceTimer = setTimeout(() => {
|
|
128
|
+
this.debounceTimer = null;
|
|
129
|
+
const changed = Array.from(this.pendingFiles);
|
|
130
|
+
this.pendingFiles.clear();
|
|
131
|
+
this.runFiles(changed, 'changed').catch((err) => {
|
|
132
|
+
console.error('Watch run error:', err.message);
|
|
133
|
+
});
|
|
134
|
+
}, this.debounceMs);
|
|
135
|
+
});
|
|
136
|
+
this.watcher.on('error', (err) => {
|
|
137
|
+
if (!this.stopped) {
|
|
138
|
+
console.error('\nWatcher error:', err.message);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
console.error(`\nrhost-testkit: Failed to start file watcher: ${err.message}`);
|
|
144
|
+
console.error('Tip: if you need recursive watching on older Linux, install chokidar: npm install chokidar --save-dev');
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// -------------------------------------------------------------------------
|
|
148
|
+
// Internal: running files
|
|
149
|
+
// -------------------------------------------------------------------------
|
|
150
|
+
async runFiles(files, reason) {
|
|
151
|
+
if (this.stopped)
|
|
152
|
+
return;
|
|
153
|
+
// Kill any already-running child process
|
|
154
|
+
if (this.currentProcess) {
|
|
155
|
+
try {
|
|
156
|
+
this.currentProcess.kill('SIGTERM');
|
|
157
|
+
}
|
|
158
|
+
catch { /* ignore */ }
|
|
159
|
+
this.currentProcess = null;
|
|
160
|
+
}
|
|
161
|
+
this.runCount++;
|
|
162
|
+
if (this.clearScreen && this.runCount > 1) {
|
|
163
|
+
process.stdout.write('\x1b[2J\x1b[H');
|
|
164
|
+
}
|
|
165
|
+
this.printRunHeader(files, reason);
|
|
166
|
+
for (const file of files) {
|
|
167
|
+
if (this.stopped)
|
|
168
|
+
break;
|
|
169
|
+
await this.spawnFile(file);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
spawnFile(file) {
|
|
173
|
+
return new Promise((resolve) => {
|
|
174
|
+
const ext = path.extname(file).toLowerCase();
|
|
175
|
+
const isTs = ext === '.ts' || ext === '.tsx';
|
|
176
|
+
// For TypeScript files, prefer ts-node via npx (always available in devDeps).
|
|
177
|
+
// For JS, use the current Node binary directly.
|
|
178
|
+
const cmd = isTs ? 'npx' : process.execPath;
|
|
179
|
+
const args = isTs ? ['ts-node', '--transpile-only', file] : [file];
|
|
180
|
+
const proc = (0, child_process_1.spawn)(cmd, args, {
|
|
181
|
+
stdio: 'inherit',
|
|
182
|
+
shell: false,
|
|
183
|
+
env: { ...process.env },
|
|
184
|
+
});
|
|
185
|
+
this.currentProcess = proc;
|
|
186
|
+
proc.on('close', () => {
|
|
187
|
+
this.currentProcess = null;
|
|
188
|
+
resolve();
|
|
189
|
+
});
|
|
190
|
+
proc.on('error', (err) => {
|
|
191
|
+
if (isTs && err.message.includes('ENOENT')) {
|
|
192
|
+
console.error(`\nrhost-testkit: could not find ts-node. Install it: npm install ts-node --save-dev`);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
console.error(`\nrhost-testkit: failed to run ${path.basename(file)}: ${err.message}`);
|
|
196
|
+
}
|
|
197
|
+
this.currentProcess = null;
|
|
198
|
+
resolve();
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
// -------------------------------------------------------------------------
|
|
203
|
+
// Internal: output formatting
|
|
204
|
+
// -------------------------------------------------------------------------
|
|
205
|
+
printBanner(files) {
|
|
206
|
+
const cwd = process.cwd();
|
|
207
|
+
const rel = files.map((f) => path.relative(cwd, f));
|
|
208
|
+
console.log('\x1b[36m╔══════════════════════════════════════════════════╗\x1b[0m');
|
|
209
|
+
console.log('\x1b[36m║\x1b[0m rhost-testkit \x1b[33mwatch mode\x1b[0m' + ' '.repeat(20) + '\x1b[36m║\x1b[0m');
|
|
210
|
+
console.log('\x1b[36m╚══════════════════════════════════════════════════╝\x1b[0m');
|
|
211
|
+
console.log(`\nWatching ${files.length} file${files.length !== 1 ? 's' : ''}:`);
|
|
212
|
+
for (const f of rel) {
|
|
213
|
+
console.log(` \x1b[90m${f}\x1b[0m`);
|
|
214
|
+
}
|
|
215
|
+
console.log('\nPress \x1b[1mCtrl+C\x1b[0m to stop.\n');
|
|
216
|
+
}
|
|
217
|
+
printRunHeader(files, reason) {
|
|
218
|
+
const sep = '─'.repeat(50);
|
|
219
|
+
const cwd = process.cwd();
|
|
220
|
+
const rel = files.map((f) => path.relative(cwd, f)).join(', ');
|
|
221
|
+
if (reason === 'initial') {
|
|
222
|
+
console.log(`\x1b[36m${sep}\x1b[0m`);
|
|
223
|
+
console.log(` \x1b[1mInitial run\x1b[0m — ${files.length} file${files.length !== 1 ? 's' : ''}`);
|
|
224
|
+
console.log(`\x1b[36m${sep}\x1b[0m\n`);
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
const now = new Date().toLocaleTimeString();
|
|
228
|
+
console.log(`\x1b[33m${sep}\x1b[0m`);
|
|
229
|
+
console.log(` \x1b[1mChanged\x1b[0m [${now}]: \x1b[33m${rel}\x1b[0m`);
|
|
230
|
+
console.log(`\x1b[33m${sep}\x1b[0m\n`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// -------------------------------------------------------------------------
|
|
234
|
+
// Internal: utilities
|
|
235
|
+
// -------------------------------------------------------------------------
|
|
236
|
+
/**
|
|
237
|
+
* Find the longest common directory path shared by all given dirs.
|
|
238
|
+
* Falls back to '/' (or drive root on Windows) if nothing in common.
|
|
239
|
+
*/
|
|
240
|
+
commonRoot(dirs) {
|
|
241
|
+
if (dirs.length === 0)
|
|
242
|
+
return process.cwd();
|
|
243
|
+
if (dirs.length === 1)
|
|
244
|
+
return dirs[0];
|
|
245
|
+
const sep = path.sep;
|
|
246
|
+
const parts = dirs.map((d) => path.resolve(d).split(sep));
|
|
247
|
+
const reference = parts[0];
|
|
248
|
+
const common = [];
|
|
249
|
+
for (let i = 0; i < reference.length; i++) {
|
|
250
|
+
if (parts.every((p) => p[i] === reference[i])) {
|
|
251
|
+
common.push(reference[i]);
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
const result = common.join(sep);
|
|
258
|
+
return result || sep;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
exports.RhostWatcher = RhostWatcher;
|
|
262
|
+
// ---------------------------------------------------------------------------
|
|
263
|
+
// File discovery helper (used by the CLI)
|
|
264
|
+
// ---------------------------------------------------------------------------
|
|
265
|
+
/**
|
|
266
|
+
* Recursively walk `rootDir` and return all test files matching
|
|
267
|
+
* `*.test.ts`, `*.test.js`, `*.spec.ts`, `*.spec.js`.
|
|
268
|
+
* Skips `node_modules`, `dist`, `.git`, `.next`, `.turbo`.
|
|
269
|
+
*/
|
|
270
|
+
function discoverTestFiles(rootDir) {
|
|
271
|
+
const files = [];
|
|
272
|
+
walkDir(path.resolve(rootDir), files);
|
|
273
|
+
return files;
|
|
274
|
+
}
|
|
275
|
+
const SKIP_DIRS = new Set(['node_modules', 'dist', '.git', '.next', '.turbo', 'coverage']);
|
|
276
|
+
const TEST_FILE_RE = /\.(test|spec)\.(ts|tsx|js|jsx)$/;
|
|
277
|
+
function walkDir(dir, out) {
|
|
278
|
+
if (SKIP_DIRS.has(path.basename(dir)))
|
|
279
|
+
return;
|
|
280
|
+
let entries;
|
|
281
|
+
try {
|
|
282
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
for (const entry of entries) {
|
|
288
|
+
const full = path.join(dir, entry.name);
|
|
289
|
+
if (entry.isDirectory()) {
|
|
290
|
+
walkDir(full, out);
|
|
291
|
+
}
|
|
292
|
+
else if (entry.isFile() && TEST_FILE_RE.test(entry.name)) {
|
|
293
|
+
out.push(full);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
//# sourceMappingURL=watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watcher.js","sourceRoot":"","sources":["../src/watcher.ts"],"names":[],"mappings":"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"}
|