webpipe-js 0.1.0 → 0.1.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/index.cjs +721 -0
- package/dist/{parser.d.ts → index.d.cts} +26 -23
- package/dist/index.d.ts +132 -0
- package/{parser.ts → dist/index.mjs} +297 -349
- package/package.json +16 -6
- package/comprehensive_test.wp +0 -1139
- package/dist/parser.js +0 -594
- package/dist/tests/parser.test.d.ts +0 -1
- package/dist/tests/parser.test.js +0 -106
- package/tests/parser.test.ts +0 -119
- package/tsconfig.json +0 -18
|
@@ -1,219 +1,101 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export interface Config {
|
|
10
|
-
name: string;
|
|
11
|
-
properties: ConfigProperty[];
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface ConfigProperty {
|
|
15
|
-
key: string;
|
|
16
|
-
value: ConfigValue;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export type ConfigValue =
|
|
20
|
-
| { kind: 'String'; value: string }
|
|
21
|
-
| { kind: 'EnvVar'; var: string; default?: string }
|
|
22
|
-
| { kind: 'Boolean'; value: boolean }
|
|
23
|
-
| { kind: 'Number'; value: number };
|
|
24
|
-
|
|
25
|
-
export interface NamedPipeline {
|
|
26
|
-
name: string;
|
|
27
|
-
pipeline: Pipeline;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface Variable {
|
|
31
|
-
varType: string;
|
|
32
|
-
name: string;
|
|
33
|
-
value: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface Route {
|
|
37
|
-
method: string;
|
|
38
|
-
path: string;
|
|
39
|
-
pipeline: PipelineRef;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export type PipelineRef =
|
|
43
|
-
| { kind: 'Inline'; pipeline: Pipeline }
|
|
44
|
-
| { kind: 'Named'; name: string };
|
|
45
|
-
|
|
46
|
-
export interface Pipeline {
|
|
47
|
-
steps: PipelineStep[];
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export type PipelineStep =
|
|
51
|
-
| { kind: 'Regular'; name: string; config: string }
|
|
52
|
-
| { kind: 'Result'; branches: ResultBranch[] };
|
|
53
|
-
|
|
54
|
-
export interface ResultBranch {
|
|
55
|
-
branchType: ResultBranchType;
|
|
56
|
-
statusCode: number;
|
|
57
|
-
pipeline: Pipeline;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export type ResultBranchType =
|
|
61
|
-
| { kind: 'Ok' }
|
|
62
|
-
| { kind: 'Custom'; name: string }
|
|
63
|
-
| { kind: 'Default' };
|
|
64
|
-
|
|
65
|
-
export interface Describe {
|
|
66
|
-
name: string;
|
|
67
|
-
mocks: Mock[];
|
|
68
|
-
tests: It[];
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export interface Mock {
|
|
72
|
-
target: string;
|
|
73
|
-
returnValue: string;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export interface It {
|
|
77
|
-
name: string;
|
|
78
|
-
mocks: Mock[];
|
|
79
|
-
when: When;
|
|
80
|
-
input?: string;
|
|
81
|
-
conditions: Condition[];
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export type When =
|
|
85
|
-
| { kind: 'CallingRoute'; method: string; path: string }
|
|
86
|
-
| { kind: 'ExecutingPipeline'; name: string }
|
|
87
|
-
| { kind: 'ExecutingVariable'; varType: string; name: string };
|
|
88
|
-
|
|
89
|
-
export interface Condition {
|
|
90
|
-
conditionType: 'Then' | 'And';
|
|
91
|
-
field: string;
|
|
92
|
-
jqExpr?: string;
|
|
93
|
-
comparison: string;
|
|
94
|
-
value: string;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export type DiagnosticSeverity = 'error' | 'warning' | 'info';
|
|
98
|
-
export interface ParseDiagnostic {
|
|
99
|
-
message: string;
|
|
100
|
-
start: number;
|
|
101
|
-
end: number;
|
|
102
|
-
severity: DiagnosticSeverity;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
class Parser {
|
|
106
|
-
private readonly text: string;
|
|
107
|
-
private readonly len: number;
|
|
108
|
-
private pos: number = 0;
|
|
109
|
-
private diagnostics: ParseDiagnostic[] = [];
|
|
110
|
-
private readonly pipelineRanges: Map<string, { start: number; end: number }> = new Map();
|
|
111
|
-
private readonly variableRanges: Map<string, { start: number; end: number }> = new Map();
|
|
112
|
-
|
|
113
|
-
constructor(text: string) {
|
|
1
|
+
// src/parser.ts
|
|
2
|
+
var Parser = class {
|
|
3
|
+
constructor(text) {
|
|
4
|
+
this.pos = 0;
|
|
5
|
+
this.diagnostics = [];
|
|
6
|
+
this.pipelineRanges = /* @__PURE__ */ new Map();
|
|
7
|
+
this.variableRanges = /* @__PURE__ */ new Map();
|
|
114
8
|
this.text = text;
|
|
115
9
|
this.len = text.length;
|
|
116
10
|
}
|
|
117
|
-
|
|
118
|
-
getDiagnostics(): ParseDiagnostic[] {
|
|
11
|
+
getDiagnostics() {
|
|
119
12
|
return this.diagnostics.slice();
|
|
120
13
|
}
|
|
121
|
-
|
|
122
|
-
getPipelineRanges(): Map<string, { start: number; end: number }> {
|
|
14
|
+
getPipelineRanges() {
|
|
123
15
|
return new Map(this.pipelineRanges);
|
|
124
16
|
}
|
|
125
|
-
|
|
126
|
-
getVariableRanges(): Map<string, { start: number; end: number }> {
|
|
17
|
+
getVariableRanges() {
|
|
127
18
|
return new Map(this.variableRanges);
|
|
128
19
|
}
|
|
129
|
-
|
|
130
|
-
report(message: string, start: number, end: number, severity: DiagnosticSeverity): void {
|
|
20
|
+
report(message, start, end, severity) {
|
|
131
21
|
this.diagnostics.push({ message, start, end, severity });
|
|
132
22
|
}
|
|
133
|
-
|
|
134
|
-
findLineStart(pos: number): number {
|
|
23
|
+
findLineStart(pos) {
|
|
135
24
|
let i = Math.max(0, Math.min(pos, this.len));
|
|
136
|
-
while (i > 0 && this.text[i - 1] !==
|
|
25
|
+
while (i > 0 && this.text[i - 1] !== "\n") i--;
|
|
137
26
|
return i;
|
|
138
27
|
}
|
|
139
|
-
|
|
140
|
-
findLineEnd(pos: number): number {
|
|
28
|
+
findLineEnd(pos) {
|
|
141
29
|
let i = Math.max(0, Math.min(pos, this.len));
|
|
142
|
-
while (i < this.text.length && this.text[i] !==
|
|
30
|
+
while (i < this.text.length && this.text[i] !== "\n") i++;
|
|
143
31
|
return i;
|
|
144
32
|
}
|
|
145
|
-
|
|
146
|
-
parseProgram(): Program {
|
|
33
|
+
parseProgram() {
|
|
147
34
|
this.skipSpaces();
|
|
148
|
-
|
|
149
|
-
const
|
|
150
|
-
const
|
|
151
|
-
const
|
|
152
|
-
const
|
|
153
|
-
const describes: Describe[] = [];
|
|
154
|
-
|
|
35
|
+
const configs = [];
|
|
36
|
+
const pipelines = [];
|
|
37
|
+
const variables = [];
|
|
38
|
+
const routes = [];
|
|
39
|
+
const describes = [];
|
|
155
40
|
while (!this.eof()) {
|
|
156
41
|
this.skipSpaces();
|
|
157
42
|
if (this.eof()) break;
|
|
158
|
-
|
|
159
43
|
const start = this.pos;
|
|
160
|
-
|
|
161
44
|
const cfg = this.tryParse(() => this.parseConfig());
|
|
162
45
|
if (cfg) {
|
|
163
46
|
configs.push(cfg);
|
|
164
47
|
continue;
|
|
165
48
|
}
|
|
166
|
-
|
|
167
49
|
const namedPipe = this.tryParse(() => this.parseNamedPipeline());
|
|
168
50
|
if (namedPipe) {
|
|
169
51
|
pipelines.push(namedPipe);
|
|
170
52
|
continue;
|
|
171
53
|
}
|
|
172
|
-
|
|
173
54
|
const variable = this.tryParse(() => this.parseVariable());
|
|
174
55
|
if (variable) {
|
|
175
56
|
variables.push(variable);
|
|
176
57
|
continue;
|
|
177
58
|
}
|
|
178
|
-
|
|
179
59
|
const route = this.tryParse(() => this.parseRoute());
|
|
180
60
|
if (route) {
|
|
181
61
|
routes.push(route);
|
|
182
62
|
continue;
|
|
183
63
|
}
|
|
184
|
-
|
|
185
64
|
const describe = this.tryParse(() => this.parseDescribe());
|
|
186
65
|
if (describe) {
|
|
187
66
|
describes.push(describe);
|
|
188
67
|
continue;
|
|
189
68
|
}
|
|
190
|
-
|
|
191
69
|
if (this.pos === start) {
|
|
192
70
|
const lineStart = this.findLineStart(this.pos);
|
|
193
71
|
const lineEnd = this.findLineEnd(this.pos);
|
|
194
|
-
this.report(
|
|
72
|
+
this.report("Unrecognized or unsupported syntax", lineStart, lineEnd, "warning");
|
|
195
73
|
this.skipToEol();
|
|
196
|
-
if (this.cur() ===
|
|
197
|
-
this.consumeWhile((c) => c ===
|
|
74
|
+
if (this.cur() === "\n") this.pos++;
|
|
75
|
+
this.consumeWhile((c) => c === "\n");
|
|
198
76
|
}
|
|
199
77
|
}
|
|
200
|
-
|
|
201
78
|
const backtickCount = (this.text.match(/`/g) || []).length;
|
|
202
79
|
if (backtickCount % 2 === 1) {
|
|
203
|
-
const idx = this.text.lastIndexOf(
|
|
80
|
+
const idx = this.text.lastIndexOf("`");
|
|
204
81
|
const start = Math.max(0, idx);
|
|
205
|
-
this.report(
|
|
82
|
+
this.report("Unclosed backtick-delimited string", start, start + 1, "warning");
|
|
206
83
|
}
|
|
207
|
-
|
|
208
84
|
return { configs, pipelines, variables, routes, describes };
|
|
209
85
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
86
|
+
eof() {
|
|
87
|
+
return this.pos >= this.len;
|
|
88
|
+
}
|
|
89
|
+
peek() {
|
|
90
|
+
return this.text[this.pos] ?? "\0";
|
|
91
|
+
}
|
|
92
|
+
cur() {
|
|
93
|
+
return this.text[this.pos] ?? "\0";
|
|
94
|
+
}
|
|
95
|
+
ahead(n) {
|
|
96
|
+
return this.text[this.pos + n] ?? "\0";
|
|
97
|
+
}
|
|
98
|
+
tryParse(fn) {
|
|
217
99
|
const save = this.pos;
|
|
218
100
|
try {
|
|
219
101
|
const value = fn();
|
|
@@ -223,74 +105,63 @@ class Parser {
|
|
|
223
105
|
return null;
|
|
224
106
|
}
|
|
225
107
|
}
|
|
226
|
-
|
|
227
|
-
private skipSpaces(): void {
|
|
108
|
+
skipSpaces() {
|
|
228
109
|
while (true) {
|
|
229
|
-
this.consumeWhile((ch) => ch ===
|
|
230
|
-
if (this.text.startsWith(
|
|
110
|
+
this.consumeWhile((ch) => ch === " " || ch === " " || ch === "\r" || ch === "\n");
|
|
111
|
+
if (this.text.startsWith("#", this.pos)) {
|
|
231
112
|
this.skipToEol();
|
|
232
|
-
if (this.cur() ===
|
|
113
|
+
if (this.cur() === "\n") this.pos++;
|
|
233
114
|
continue;
|
|
234
115
|
}
|
|
235
|
-
if (this.text.startsWith(
|
|
116
|
+
if (this.text.startsWith("//", this.pos)) {
|
|
236
117
|
this.skipToEol();
|
|
237
|
-
if (this.cur() ===
|
|
118
|
+
if (this.cur() === "\n") this.pos++;
|
|
238
119
|
continue;
|
|
239
120
|
}
|
|
240
121
|
break;
|
|
241
122
|
}
|
|
242
123
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
this.consumeWhile((ch) => ch === ' ' || ch === '\t' || ch === '\r');
|
|
124
|
+
skipInlineSpaces() {
|
|
125
|
+
this.consumeWhile((ch) => ch === " " || ch === " " || ch === "\r");
|
|
246
126
|
}
|
|
247
|
-
|
|
248
|
-
private consumeWhile(pred: (ch: string) => boolean): string {
|
|
127
|
+
consumeWhile(pred) {
|
|
249
128
|
const start = this.pos;
|
|
250
129
|
while (!this.eof() && pred(this.text[this.pos])) this.pos++;
|
|
251
130
|
return this.text.slice(start, this.pos);
|
|
252
131
|
}
|
|
253
|
-
|
|
254
|
-
private match(str: string): boolean {
|
|
132
|
+
match(str) {
|
|
255
133
|
if (this.text.startsWith(str, this.pos)) {
|
|
256
134
|
this.pos += str.length;
|
|
257
135
|
return true;
|
|
258
136
|
}
|
|
259
137
|
return false;
|
|
260
138
|
}
|
|
261
|
-
|
|
262
|
-
private expect(str: string): void {
|
|
139
|
+
expect(str) {
|
|
263
140
|
if (!this.match(str)) throw new ParseFailure(`expected '${str}'`, this.pos);
|
|
264
141
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
while (!this.eof() && this.cur() !== '\n') this.pos++;
|
|
142
|
+
skipToEol() {
|
|
143
|
+
while (!this.eof() && this.cur() !== "\n") this.pos++;
|
|
268
144
|
}
|
|
269
|
-
|
|
270
|
-
private isIdentStart(ch: string): boolean {
|
|
145
|
+
isIdentStart(ch) {
|
|
271
146
|
return /[A-Za-z_]/.test(ch);
|
|
272
147
|
}
|
|
273
|
-
|
|
274
|
-
private isIdentCont(ch: string): boolean {
|
|
148
|
+
isIdentCont(ch) {
|
|
275
149
|
return /[A-Za-z0-9_\-]/.test(ch);
|
|
276
150
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
if (!this.isIdentStart(this.cur())) throw new ParseFailure('identifier', this.pos);
|
|
151
|
+
parseIdentifier() {
|
|
152
|
+
if (!this.isIdentStart(this.cur())) throw new ParseFailure("identifier", this.pos);
|
|
280
153
|
const start = this.pos;
|
|
281
154
|
this.pos++;
|
|
282
155
|
while (!this.eof() && this.isIdentCont(this.cur())) this.pos++;
|
|
283
156
|
return this.text.slice(start, this.pos);
|
|
284
157
|
}
|
|
285
|
-
|
|
286
|
-
private parseNumber(): number {
|
|
158
|
+
parseNumber() {
|
|
287
159
|
const start = this.pos;
|
|
288
160
|
const digits = this.consumeWhile((c) => /[0-9]/.test(c));
|
|
289
|
-
if (digits.length === 0) throw new ParseFailure(
|
|
161
|
+
if (digits.length === 0) throw new ParseFailure("number", this.pos);
|
|
290
162
|
return parseInt(this.text.slice(start, this.pos), 10);
|
|
291
163
|
}
|
|
292
|
-
|
|
293
|
-
private parseQuotedString(): string {
|
|
164
|
+
parseQuotedString() {
|
|
294
165
|
this.expect('"');
|
|
295
166
|
const start = this.pos;
|
|
296
167
|
while (!this.eof()) {
|
|
@@ -302,94 +173,83 @@ class Parser {
|
|
|
302
173
|
this.expect('"');
|
|
303
174
|
return content;
|
|
304
175
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
this.expect('`');
|
|
176
|
+
parseBacktickString() {
|
|
177
|
+
this.expect("`");
|
|
308
178
|
const start = this.pos;
|
|
309
179
|
while (!this.eof()) {
|
|
310
180
|
const ch = this.cur();
|
|
311
|
-
if (ch ===
|
|
181
|
+
if (ch === "`") break;
|
|
312
182
|
this.pos++;
|
|
313
183
|
}
|
|
314
184
|
const content = this.text.slice(start, this.pos);
|
|
315
|
-
this.expect(
|
|
185
|
+
this.expect("`");
|
|
316
186
|
return content;
|
|
317
187
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
const methods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];
|
|
188
|
+
parseMethod() {
|
|
189
|
+
const methods = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
321
190
|
for (const m of methods) {
|
|
322
191
|
if (this.text.startsWith(m, this.pos)) {
|
|
323
192
|
this.pos += m.length;
|
|
324
193
|
return m;
|
|
325
194
|
}
|
|
326
195
|
}
|
|
327
|
-
throw new ParseFailure(
|
|
196
|
+
throw new ParseFailure("method", this.pos);
|
|
328
197
|
}
|
|
329
|
-
|
|
330
|
-
private parseStepConfig(): string {
|
|
198
|
+
parseStepConfig() {
|
|
331
199
|
const bt = this.tryParse(() => this.parseBacktickString());
|
|
332
200
|
if (bt !== null) return bt;
|
|
333
201
|
const dq = this.tryParse(() => this.parseQuotedString());
|
|
334
202
|
if (dq !== null) return dq;
|
|
335
203
|
const id = this.tryParse(() => this.parseIdentifier());
|
|
336
204
|
if (id !== null) return id;
|
|
337
|
-
throw new ParseFailure(
|
|
205
|
+
throw new ParseFailure("step-config", this.pos);
|
|
338
206
|
}
|
|
339
|
-
|
|
340
|
-
private parseConfigValue(): ConfigValue {
|
|
207
|
+
parseConfigValue() {
|
|
341
208
|
const envWithDefault = this.tryParse(() => {
|
|
342
|
-
this.expect(
|
|
209
|
+
this.expect("$");
|
|
343
210
|
const variable = this.parseIdentifier();
|
|
344
211
|
this.skipInlineSpaces();
|
|
345
|
-
this.expect(
|
|
212
|
+
this.expect("||");
|
|
346
213
|
this.skipInlineSpaces();
|
|
347
214
|
const def = this.parseQuotedString();
|
|
348
|
-
return { kind:
|
|
215
|
+
return { kind: "EnvVar", var: variable, default: def };
|
|
349
216
|
});
|
|
350
217
|
if (envWithDefault) return envWithDefault;
|
|
351
|
-
|
|
352
218
|
const envNoDefault = this.tryParse(() => {
|
|
353
|
-
this.expect(
|
|
219
|
+
this.expect("$");
|
|
354
220
|
const variable = this.parseIdentifier();
|
|
355
|
-
return { kind:
|
|
221
|
+
return { kind: "EnvVar", var: variable };
|
|
356
222
|
});
|
|
357
223
|
if (envNoDefault) return envNoDefault;
|
|
358
|
-
|
|
359
224
|
const str = this.tryParse(() => this.parseQuotedString());
|
|
360
|
-
if (str !== null) return { kind:
|
|
361
|
-
|
|
225
|
+
if (str !== null) return { kind: "String", value: str };
|
|
362
226
|
const bool = this.tryParse(() => {
|
|
363
|
-
if (this.match(
|
|
364
|
-
if (this.match(
|
|
365
|
-
throw new ParseFailure(
|
|
227
|
+
if (this.match("true")) return true;
|
|
228
|
+
if (this.match("false")) return false;
|
|
229
|
+
throw new ParseFailure("bool", this.pos);
|
|
366
230
|
});
|
|
367
|
-
if (bool !== null) return { kind:
|
|
368
|
-
|
|
231
|
+
if (bool !== null) return { kind: "Boolean", value: bool };
|
|
369
232
|
const num = this.tryParse(() => this.parseNumber());
|
|
370
|
-
if (num !== null) return { kind:
|
|
371
|
-
|
|
372
|
-
throw new ParseFailure('config-value', this.pos);
|
|
233
|
+
if (num !== null) return { kind: "Number", value: num };
|
|
234
|
+
throw new ParseFailure("config-value", this.pos);
|
|
373
235
|
}
|
|
374
|
-
|
|
375
|
-
private parseConfigProperty(): ConfigProperty {
|
|
236
|
+
parseConfigProperty() {
|
|
376
237
|
this.skipSpaces();
|
|
377
238
|
const key = this.parseIdentifier();
|
|
378
239
|
this.skipInlineSpaces();
|
|
379
|
-
this.expect(
|
|
240
|
+
this.expect(":");
|
|
380
241
|
this.skipInlineSpaces();
|
|
381
242
|
const value = this.parseConfigValue();
|
|
382
243
|
return { key, value };
|
|
383
244
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
this.expect('config');
|
|
245
|
+
parseConfig() {
|
|
246
|
+
this.expect("config");
|
|
387
247
|
this.skipInlineSpaces();
|
|
388
248
|
const name = this.parseIdentifier();
|
|
389
249
|
this.skipInlineSpaces();
|
|
390
|
-
this.expect(
|
|
250
|
+
this.expect("{");
|
|
391
251
|
this.skipSpaces();
|
|
392
|
-
const properties
|
|
252
|
+
const properties = [];
|
|
393
253
|
while (true) {
|
|
394
254
|
const prop = this.tryParse(() => this.parseConfigProperty());
|
|
395
255
|
if (!prop) break;
|
|
@@ -397,72 +257,69 @@ class Parser {
|
|
|
397
257
|
this.skipSpaces();
|
|
398
258
|
}
|
|
399
259
|
this.skipSpaces();
|
|
400
|
-
this.expect(
|
|
260
|
+
this.expect("}");
|
|
401
261
|
this.skipSpaces();
|
|
402
262
|
return { name, properties };
|
|
403
263
|
}
|
|
404
|
-
|
|
405
|
-
private parsePipelineStep(): PipelineStep {
|
|
264
|
+
parsePipelineStep() {
|
|
406
265
|
const result = this.tryParse(() => this.parseResultStep());
|
|
407
266
|
if (result) return result;
|
|
408
267
|
return this.parseRegularStep();
|
|
409
268
|
}
|
|
410
|
-
|
|
411
|
-
private parseRegularStep(): PipelineStep {
|
|
269
|
+
parseRegularStep() {
|
|
412
270
|
this.skipSpaces();
|
|
413
|
-
this.expect(
|
|
271
|
+
this.expect("|>");
|
|
414
272
|
this.skipInlineSpaces();
|
|
415
273
|
const name = this.parseIdentifier();
|
|
416
|
-
this.expect(
|
|
274
|
+
this.expect(":");
|
|
417
275
|
this.skipInlineSpaces();
|
|
418
276
|
const config = this.parseStepConfig();
|
|
419
277
|
this.skipSpaces();
|
|
420
|
-
return { kind:
|
|
278
|
+
return { kind: "Regular", name, config };
|
|
421
279
|
}
|
|
422
|
-
|
|
423
|
-
private parseResultStep(): PipelineStep {
|
|
280
|
+
parseResultStep() {
|
|
424
281
|
this.skipSpaces();
|
|
425
|
-
this.expect(
|
|
282
|
+
this.expect("|>");
|
|
426
283
|
this.skipInlineSpaces();
|
|
427
|
-
this.expect(
|
|
284
|
+
this.expect("result");
|
|
428
285
|
this.skipSpaces();
|
|
429
|
-
const branches
|
|
286
|
+
const branches = [];
|
|
430
287
|
while (true) {
|
|
431
288
|
const br = this.tryParse(() => this.parseResultBranch());
|
|
432
289
|
if (!br) break;
|
|
433
290
|
branches.push(br);
|
|
434
291
|
}
|
|
435
|
-
return { kind:
|
|
292
|
+
return { kind: "Result", branches };
|
|
436
293
|
}
|
|
437
|
-
|
|
438
|
-
private parseResultBranch(): ResultBranch {
|
|
294
|
+
parseResultBranch() {
|
|
439
295
|
this.skipSpaces();
|
|
440
296
|
const branchIdent = this.parseIdentifier();
|
|
441
|
-
let branchType
|
|
442
|
-
if (branchIdent ===
|
|
443
|
-
else if (branchIdent ===
|
|
444
|
-
else branchType = { kind:
|
|
445
|
-
this.expect(
|
|
297
|
+
let branchType;
|
|
298
|
+
if (branchIdent === "ok") branchType = { kind: "Ok" };
|
|
299
|
+
else if (branchIdent === "default") branchType = { kind: "Default" };
|
|
300
|
+
else branchType = { kind: "Custom", name: branchIdent };
|
|
301
|
+
this.expect("(");
|
|
446
302
|
const statusCode = this.parseNumber();
|
|
447
303
|
if (statusCode < 100 || statusCode > 599) {
|
|
448
|
-
this.report(
|
|
304
|
+
this.report(
|
|
305
|
+
`Invalid HTTP status code: ${statusCode}`,
|
|
449
306
|
this.pos - String(statusCode).length,
|
|
450
307
|
this.pos,
|
|
451
|
-
|
|
308
|
+
"error"
|
|
309
|
+
);
|
|
452
310
|
}
|
|
453
|
-
this.expect(
|
|
454
|
-
this.expect(
|
|
311
|
+
this.expect(")");
|
|
312
|
+
this.expect(":");
|
|
455
313
|
this.skipSpaces();
|
|
456
314
|
const pipeline = this.parsePipeline();
|
|
457
315
|
return { branchType, statusCode, pipeline };
|
|
458
316
|
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
const steps: PipelineStep[] = [];
|
|
317
|
+
parsePipeline() {
|
|
318
|
+
const steps = [];
|
|
462
319
|
while (true) {
|
|
463
320
|
const save = this.pos;
|
|
464
321
|
this.skipSpaces();
|
|
465
|
-
if (!this.text.startsWith(
|
|
322
|
+
if (!this.text.startsWith("|>", this.pos)) {
|
|
466
323
|
this.pos = save;
|
|
467
324
|
break;
|
|
468
325
|
}
|
|
@@ -471,14 +328,13 @@ class Parser {
|
|
|
471
328
|
}
|
|
472
329
|
return { steps };
|
|
473
330
|
}
|
|
474
|
-
|
|
475
|
-
private parseNamedPipeline(): NamedPipeline {
|
|
331
|
+
parseNamedPipeline() {
|
|
476
332
|
const start = this.pos;
|
|
477
|
-
this.expect(
|
|
333
|
+
this.expect("pipeline");
|
|
478
334
|
this.skipInlineSpaces();
|
|
479
335
|
const name = this.parseIdentifier();
|
|
480
336
|
this.skipInlineSpaces();
|
|
481
|
-
this.expect(
|
|
337
|
+
this.expect("=");
|
|
482
338
|
this.skipInlineSpaces();
|
|
483
339
|
const beforePipeline = this.pos;
|
|
484
340
|
const pipeline = this.parsePipeline();
|
|
@@ -487,31 +343,28 @@ class Parser {
|
|
|
487
343
|
this.skipSpaces();
|
|
488
344
|
return { name, pipeline };
|
|
489
345
|
}
|
|
490
|
-
|
|
491
|
-
private parsePipelineRef(): PipelineRef {
|
|
346
|
+
parsePipelineRef() {
|
|
492
347
|
const inline = this.tryParse(() => this.parsePipeline());
|
|
493
|
-
if (inline && inline.steps.length > 0) return { kind:
|
|
494
|
-
|
|
348
|
+
if (inline && inline.steps.length > 0) return { kind: "Inline", pipeline: inline };
|
|
495
349
|
const named = this.tryParse(() => {
|
|
496
350
|
this.skipSpaces();
|
|
497
|
-
this.expect(
|
|
351
|
+
this.expect("|>");
|
|
498
352
|
this.skipInlineSpaces();
|
|
499
|
-
this.expect(
|
|
353
|
+
this.expect("pipeline:");
|
|
500
354
|
this.skipInlineSpaces();
|
|
501
355
|
const name = this.parseIdentifier();
|
|
502
|
-
return { kind:
|
|
356
|
+
return { kind: "Named", name };
|
|
503
357
|
});
|
|
504
358
|
if (named) return named;
|
|
505
|
-
throw new Error(
|
|
359
|
+
throw new Error("pipeline-ref");
|
|
506
360
|
}
|
|
507
|
-
|
|
508
|
-
private parseVariable(): Variable {
|
|
361
|
+
parseVariable() {
|
|
509
362
|
const start = this.pos;
|
|
510
363
|
const varType = this.parseIdentifier();
|
|
511
364
|
this.skipInlineSpaces();
|
|
512
365
|
const name = this.parseIdentifier();
|
|
513
366
|
this.skipInlineSpaces();
|
|
514
|
-
this.expect(
|
|
367
|
+
this.expect("=");
|
|
515
368
|
this.skipInlineSpaces();
|
|
516
369
|
const value = this.parseBacktickString();
|
|
517
370
|
const end = this.pos;
|
|
@@ -519,213 +372,308 @@ class Parser {
|
|
|
519
372
|
this.skipSpaces();
|
|
520
373
|
return { varType, name, value };
|
|
521
374
|
}
|
|
522
|
-
|
|
523
|
-
private parseRoute(): Route {
|
|
375
|
+
parseRoute() {
|
|
524
376
|
const method = this.parseMethod();
|
|
525
377
|
this.skipInlineSpaces();
|
|
526
|
-
const path = this.consumeWhile((c) => c !==
|
|
378
|
+
const path = this.consumeWhile((c) => c !== " " && c !== "\n");
|
|
527
379
|
this.skipSpaces();
|
|
528
380
|
const pipeline = this.parsePipelineRef();
|
|
529
381
|
this.skipSpaces();
|
|
530
382
|
return { method, path, pipeline };
|
|
531
383
|
}
|
|
532
|
-
|
|
533
|
-
private parseWhen(): When {
|
|
384
|
+
parseWhen() {
|
|
534
385
|
const calling = this.tryParse(() => {
|
|
535
|
-
this.expect(
|
|
386
|
+
this.expect("calling");
|
|
536
387
|
this.skipInlineSpaces();
|
|
537
388
|
const method = this.parseMethod();
|
|
538
389
|
this.skipInlineSpaces();
|
|
539
|
-
const path = this.consumeWhile((c) => c !==
|
|
540
|
-
return { kind:
|
|
390
|
+
const path = this.consumeWhile((c) => c !== "\n");
|
|
391
|
+
return { kind: "CallingRoute", method, path };
|
|
541
392
|
});
|
|
542
393
|
if (calling) return calling;
|
|
543
|
-
|
|
544
394
|
const executingPipeline = this.tryParse(() => {
|
|
545
|
-
this.expect(
|
|
395
|
+
this.expect("executing");
|
|
546
396
|
this.skipInlineSpaces();
|
|
547
|
-
this.expect(
|
|
397
|
+
this.expect("pipeline");
|
|
548
398
|
this.skipInlineSpaces();
|
|
549
399
|
const name = this.parseIdentifier();
|
|
550
|
-
return { kind:
|
|
400
|
+
return { kind: "ExecutingPipeline", name };
|
|
551
401
|
});
|
|
552
402
|
if (executingPipeline) return executingPipeline;
|
|
553
|
-
|
|
554
403
|
const executingVariable = this.tryParse(() => {
|
|
555
|
-
this.expect(
|
|
404
|
+
this.expect("executing");
|
|
556
405
|
this.skipInlineSpaces();
|
|
557
|
-
this.expect(
|
|
406
|
+
this.expect("variable");
|
|
558
407
|
this.skipInlineSpaces();
|
|
559
408
|
const varType = this.parseIdentifier();
|
|
560
409
|
this.skipInlineSpaces();
|
|
561
410
|
const name = this.parseIdentifier();
|
|
562
|
-
return { kind:
|
|
411
|
+
return { kind: "ExecutingVariable", varType, name };
|
|
563
412
|
});
|
|
564
413
|
if (executingVariable) return executingVariable;
|
|
565
|
-
|
|
566
|
-
throw new ParseFailure('when', this.pos);
|
|
414
|
+
throw new ParseFailure("when", this.pos);
|
|
567
415
|
}
|
|
568
|
-
|
|
569
|
-
private parseCondition(): Condition {
|
|
416
|
+
parseCondition() {
|
|
570
417
|
this.skipSpaces();
|
|
571
418
|
const ct = (() => {
|
|
572
|
-
if (this.match(
|
|
573
|
-
if (this.match(
|
|
574
|
-
throw new Error(
|
|
419
|
+
if (this.match("then")) return "Then";
|
|
420
|
+
if (this.match("and")) return "And";
|
|
421
|
+
throw new Error("condition-type");
|
|
575
422
|
})();
|
|
576
423
|
this.skipInlineSpaces();
|
|
577
|
-
const field = this.consumeWhile((c) => c !==
|
|
424
|
+
const field = this.consumeWhile((c) => c !== " " && c !== "\n" && c !== "`");
|
|
578
425
|
this.skipInlineSpaces();
|
|
579
426
|
const jqExpr = this.tryParse(() => this.parseBacktickString());
|
|
580
427
|
this.skipInlineSpaces();
|
|
581
|
-
const comparison = this.consumeWhile((c) => c !==
|
|
428
|
+
const comparison = this.consumeWhile((c) => c !== " " && c !== "\n");
|
|
582
429
|
this.skipInlineSpaces();
|
|
583
430
|
const value = (() => {
|
|
584
431
|
const v1 = this.tryParse(() => this.parseBacktickString());
|
|
585
432
|
if (v1 !== null) return v1;
|
|
586
433
|
const v2 = this.tryParse(() => this.parseQuotedString());
|
|
587
434
|
if (v2 !== null) return v2;
|
|
588
|
-
return this.consumeWhile((c) => c !==
|
|
435
|
+
return this.consumeWhile((c) => c !== "\n");
|
|
589
436
|
})();
|
|
590
|
-
return { conditionType: ct, field, jqExpr: jqExpr ??
|
|
437
|
+
return { conditionType: ct, field, jqExpr: jqExpr ?? void 0, comparison, value };
|
|
591
438
|
}
|
|
592
|
-
|
|
593
|
-
private parseMockHead(prefixWord: 'with' | 'and'): Mock {
|
|
439
|
+
parseMockHead(prefixWord) {
|
|
594
440
|
this.skipSpaces();
|
|
595
441
|
this.expect(prefixWord);
|
|
596
442
|
this.skipInlineSpaces();
|
|
597
|
-
this.expect(
|
|
443
|
+
this.expect("mock");
|
|
598
444
|
this.skipInlineSpaces();
|
|
599
|
-
const target = this.consumeWhile((c) => c !==
|
|
445
|
+
const target = this.consumeWhile((c) => c !== " " && c !== "\n");
|
|
600
446
|
this.skipInlineSpaces();
|
|
601
|
-
this.expect(
|
|
447
|
+
this.expect("returning");
|
|
602
448
|
this.skipInlineSpaces();
|
|
603
449
|
const returnValue = this.parseBacktickString();
|
|
604
450
|
this.skipSpaces();
|
|
605
451
|
return { target, returnValue };
|
|
606
452
|
}
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
return this.parseMockHead('with');
|
|
453
|
+
parseMock() {
|
|
454
|
+
return this.parseMockHead("with");
|
|
610
455
|
}
|
|
611
|
-
|
|
612
|
-
return this.parseMockHead(
|
|
456
|
+
parseAndMock() {
|
|
457
|
+
return this.parseMockHead("and");
|
|
613
458
|
}
|
|
614
|
-
|
|
615
|
-
private parseIt(): It {
|
|
459
|
+
parseIt() {
|
|
616
460
|
this.skipSpaces();
|
|
617
|
-
this.expect(
|
|
461
|
+
this.expect("it");
|
|
618
462
|
this.skipInlineSpaces();
|
|
619
463
|
this.expect('"');
|
|
620
464
|
const name = this.consumeWhile((c) => c !== '"');
|
|
621
465
|
this.expect('"');
|
|
622
466
|
this.skipSpaces();
|
|
623
|
-
|
|
624
|
-
const mocks: Mock[] = [];
|
|
467
|
+
const mocks = [];
|
|
625
468
|
while (true) {
|
|
626
469
|
const m = this.tryParse(() => this.parseMock());
|
|
627
470
|
if (!m) break;
|
|
628
471
|
mocks.push(m);
|
|
629
472
|
}
|
|
630
|
-
|
|
631
|
-
this.expect('when');
|
|
473
|
+
this.expect("when");
|
|
632
474
|
this.skipInlineSpaces();
|
|
633
475
|
const when = this.parseWhen();
|
|
634
476
|
this.skipSpaces();
|
|
635
|
-
|
|
636
477
|
const input = this.tryParse(() => {
|
|
637
|
-
this.expect(
|
|
478
|
+
this.expect("with");
|
|
638
479
|
this.skipInlineSpaces();
|
|
639
|
-
this.expect(
|
|
480
|
+
this.expect("input");
|
|
640
481
|
this.skipInlineSpaces();
|
|
641
482
|
const v = this.parseBacktickString();
|
|
642
483
|
this.skipSpaces();
|
|
643
484
|
return v;
|
|
644
|
-
}) ??
|
|
645
|
-
|
|
646
|
-
const extraMocks: Mock[] = [];
|
|
485
|
+
}) ?? void 0;
|
|
486
|
+
const extraMocks = [];
|
|
647
487
|
while (true) {
|
|
648
488
|
const m = this.tryParse(() => this.parseAndMock());
|
|
649
489
|
if (!m) break;
|
|
650
490
|
extraMocks.push(m);
|
|
651
491
|
this.skipSpaces();
|
|
652
492
|
}
|
|
653
|
-
|
|
654
|
-
const conditions: Condition[] = [];
|
|
493
|
+
const conditions = [];
|
|
655
494
|
while (true) {
|
|
656
495
|
const c = this.tryParse(() => this.parseCondition());
|
|
657
496
|
if (!c) break;
|
|
658
497
|
conditions.push(c);
|
|
659
498
|
}
|
|
660
|
-
|
|
661
499
|
return { name, mocks: [...mocks, ...extraMocks], when, input, conditions };
|
|
662
500
|
}
|
|
663
|
-
|
|
664
|
-
private parseDescribe(): Describe {
|
|
501
|
+
parseDescribe() {
|
|
665
502
|
this.skipSpaces();
|
|
666
|
-
this.expect(
|
|
503
|
+
this.expect("describe");
|
|
667
504
|
this.skipInlineSpaces();
|
|
668
505
|
this.expect('"');
|
|
669
506
|
const name = this.consumeWhile((c) => c !== '"');
|
|
670
507
|
this.expect('"');
|
|
671
508
|
this.skipSpaces();
|
|
672
|
-
|
|
673
|
-
const mocks: Mock[] = [];
|
|
509
|
+
const mocks = [];
|
|
674
510
|
while (true) {
|
|
675
511
|
const m = this.tryParse(() => this.parseMock());
|
|
676
512
|
if (!m) break;
|
|
677
513
|
mocks.push(m);
|
|
678
514
|
this.skipSpaces();
|
|
679
515
|
}
|
|
680
|
-
|
|
681
|
-
const tests: It[] = [];
|
|
516
|
+
const tests = [];
|
|
682
517
|
while (true) {
|
|
683
518
|
const it = this.tryParse(() => this.parseIt());
|
|
684
519
|
if (!it) break;
|
|
685
520
|
tests.push(it);
|
|
686
521
|
}
|
|
687
|
-
|
|
688
522
|
return { name, mocks, tests };
|
|
689
523
|
}
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
export function parseProgram(text: string): Program {
|
|
524
|
+
};
|
|
525
|
+
function parseProgram(text) {
|
|
693
526
|
const parser = new Parser(text);
|
|
694
527
|
return parser.parseProgram();
|
|
695
528
|
}
|
|
696
|
-
|
|
697
|
-
export function parseProgramWithDiagnostics(text: string): { program: Program; diagnostics: ParseDiagnostic[] } {
|
|
529
|
+
function parseProgramWithDiagnostics(text) {
|
|
698
530
|
const parser = new Parser(text);
|
|
699
531
|
const program = parser.parseProgram();
|
|
700
532
|
return { program, diagnostics: parser.getDiagnostics() };
|
|
701
533
|
}
|
|
702
|
-
|
|
703
|
-
export function getPipelineRanges(text: string): Map<string, { start: number; end: number }> {
|
|
534
|
+
function getPipelineRanges(text) {
|
|
704
535
|
const parser = new Parser(text);
|
|
705
536
|
parser.parseProgram();
|
|
706
537
|
return parser.getPipelineRanges();
|
|
707
538
|
}
|
|
708
|
-
|
|
709
|
-
export function getVariableRanges(text: string): Map<string, { start: number; end: number }> {
|
|
539
|
+
function getVariableRanges(text) {
|
|
710
540
|
const parser = new Parser(text);
|
|
711
541
|
parser.parseProgram();
|
|
712
542
|
return parser.getVariableRanges();
|
|
713
543
|
}
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
constructor(message: string, public at: number) {
|
|
544
|
+
var ParseFailure = class extends Error {
|
|
545
|
+
constructor(message, at) {
|
|
717
546
|
super(message);
|
|
547
|
+
this.at = at;
|
|
548
|
+
}
|
|
549
|
+
};
|
|
550
|
+
function prettyPrint(program) {
|
|
551
|
+
const lines = [];
|
|
552
|
+
program.configs.forEach((config) => {
|
|
553
|
+
lines.push(`config ${config.name} {`);
|
|
554
|
+
config.properties.forEach((prop) => {
|
|
555
|
+
const value = formatConfigValue(prop.value);
|
|
556
|
+
lines.push(` ${prop.key}: ${value}`);
|
|
557
|
+
});
|
|
558
|
+
lines.push("}");
|
|
559
|
+
lines.push("");
|
|
560
|
+
});
|
|
561
|
+
program.variables.forEach((variable) => {
|
|
562
|
+
lines.push(`${variable.varType} ${variable.name} = \`${variable.value}\``);
|
|
563
|
+
});
|
|
564
|
+
if (program.variables.length > 0) lines.push("");
|
|
565
|
+
program.pipelines.forEach((pipeline) => {
|
|
566
|
+
lines.push(`pipeline ${pipeline.name} =`);
|
|
567
|
+
pipeline.pipeline.steps.forEach((step) => {
|
|
568
|
+
lines.push(formatPipelineStep(step));
|
|
569
|
+
});
|
|
570
|
+
lines.push("");
|
|
571
|
+
});
|
|
572
|
+
program.routes.forEach((route) => {
|
|
573
|
+
lines.push(`${route.method} ${route.path}`);
|
|
574
|
+
const pipelineLines = formatPipelineRef(route.pipeline);
|
|
575
|
+
pipelineLines.forEach((line) => lines.push(line));
|
|
576
|
+
lines.push("");
|
|
577
|
+
});
|
|
578
|
+
program.describes.forEach((describe) => {
|
|
579
|
+
lines.push(`describe "${describe.name}"`);
|
|
580
|
+
describe.mocks.forEach((mock) => {
|
|
581
|
+
lines.push(` with mock ${mock.target} returning \`${mock.returnValue}\``);
|
|
582
|
+
});
|
|
583
|
+
lines.push("");
|
|
584
|
+
describe.tests.forEach((test) => {
|
|
585
|
+
lines.push(` it "${test.name}"`);
|
|
586
|
+
test.mocks.forEach((mock) => {
|
|
587
|
+
lines.push(` with mock ${mock.target} returning \`${mock.returnValue}\``);
|
|
588
|
+
});
|
|
589
|
+
lines.push(` when ${formatWhen(test.when)}`);
|
|
590
|
+
if (test.input) {
|
|
591
|
+
lines.push(` with input \`${test.input}\``);
|
|
592
|
+
}
|
|
593
|
+
test.conditions.forEach((condition) => {
|
|
594
|
+
const condType = condition.conditionType.toLowerCase();
|
|
595
|
+
const jqPart = condition.jqExpr ? ` \`${condition.jqExpr}\`` : "";
|
|
596
|
+
lines.push(` ${condType} ${condition.field}${jqPart} ${condition.comparison} ${condition.value}`);
|
|
597
|
+
});
|
|
598
|
+
lines.push("");
|
|
599
|
+
});
|
|
600
|
+
});
|
|
601
|
+
return lines.join("\n").trim();
|
|
602
|
+
}
|
|
603
|
+
function formatConfigValue(value) {
|
|
604
|
+
switch (value.kind) {
|
|
605
|
+
case "String":
|
|
606
|
+
return `"${value.value}"`;
|
|
607
|
+
case "EnvVar":
|
|
608
|
+
return value.default ? `$${value.var} || "${value.default}"` : `$${value.var}`;
|
|
609
|
+
case "Boolean":
|
|
610
|
+
return value.value.toString();
|
|
611
|
+
case "Number":
|
|
612
|
+
return value.value.toString();
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
function formatPipelineStep(step, indent = " ") {
|
|
616
|
+
if (step.kind === "Regular") {
|
|
617
|
+
return `${indent}|> ${step.name}: ${formatStepConfig(step.config)}`;
|
|
618
|
+
} else {
|
|
619
|
+
const lines = [`${indent}|> result`];
|
|
620
|
+
step.branches.forEach((branch) => {
|
|
621
|
+
const branchName = branch.branchType.kind === "Ok" ? "ok" : branch.branchType.kind === "Default" ? "default" : branch.branchType.name;
|
|
622
|
+
lines.push(`${indent} ${branchName}(${branch.statusCode}):`);
|
|
623
|
+
branch.pipeline.steps.forEach((branchStep) => {
|
|
624
|
+
lines.push(formatPipelineStep(branchStep, indent + " "));
|
|
625
|
+
});
|
|
626
|
+
});
|
|
627
|
+
return lines.join("\n");
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
function formatStepConfig(config) {
|
|
631
|
+
if (config.includes("`")) {
|
|
632
|
+
return `\`${config}\``;
|
|
633
|
+
} else if (config.includes(" ") || config.includes("\n")) {
|
|
634
|
+
return `"${config}"`;
|
|
635
|
+
} else {
|
|
636
|
+
return config;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
function formatPipelineRef(ref) {
|
|
640
|
+
if (ref.kind === "Named") {
|
|
641
|
+
return [` |> pipeline: ${ref.name}`];
|
|
642
|
+
} else {
|
|
643
|
+
const lines = [];
|
|
644
|
+
ref.pipeline.steps.forEach((step) => {
|
|
645
|
+
lines.push(formatPipelineStep(step));
|
|
646
|
+
});
|
|
647
|
+
return lines;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
function formatWhen(when) {
|
|
651
|
+
switch (when.kind) {
|
|
652
|
+
case "CallingRoute":
|
|
653
|
+
return `calling ${when.method} ${when.path}`;
|
|
654
|
+
case "ExecutingPipeline":
|
|
655
|
+
return `executing pipeline ${when.name}`;
|
|
656
|
+
case "ExecutingVariable":
|
|
657
|
+
return `executing variable ${when.varType} ${when.name}`;
|
|
718
658
|
}
|
|
719
659
|
}
|
|
720
|
-
|
|
721
660
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
722
|
-
|
|
661
|
+
(async () => {
|
|
662
|
+
const fs = await import("fs/promises");
|
|
723
663
|
const path = process.argv[2];
|
|
724
664
|
if (!path) {
|
|
725
|
-
|
|
726
|
-
|
|
665
|
+
console.error("Usage: node dist/index.mjs <file.wp>");
|
|
666
|
+
process.exit(1);
|
|
727
667
|
}
|
|
728
|
-
const src = await fs.readFile(path,
|
|
668
|
+
const src = await fs.readFile(path, "utf8");
|
|
729
669
|
const program = parseProgram(src);
|
|
730
670
|
console.log(JSON.stringify(program, null, 2));
|
|
671
|
+
})();
|
|
731
672
|
}
|
|
673
|
+
export {
|
|
674
|
+
getPipelineRanges,
|
|
675
|
+
getVariableRanges,
|
|
676
|
+
parseProgram,
|
|
677
|
+
parseProgramWithDiagnostics,
|
|
678
|
+
prettyPrint
|
|
679
|
+
};
|