cloudflare-expression-lint 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/dist/parser.js ADDED
@@ -0,0 +1,320 @@
1
+ /**
2
+ * Parser for Cloudflare expressions.
3
+ *
4
+ * Converts a token stream into an AST using recursive descent parsing.
5
+ * Handles operator precedence for logical operators:
6
+ * 1. not / ! (highest, unary)
7
+ * 2. and / &&
8
+ * 3. xor / ^^
9
+ * 4. or / || (lowest)
10
+ */
11
+ import { tokenize } from './lexer.js';
12
+ import { TokenType, } from './types.js';
13
+ class Parser {
14
+ tokens;
15
+ pos = 0;
16
+ constructor(tokens) {
17
+ this.tokens = tokens;
18
+ }
19
+ peek() {
20
+ return this.tokens[this.pos] ?? this.eof();
21
+ }
22
+ peekType() {
23
+ return this.peek().type;
24
+ }
25
+ advance() {
26
+ const token = this.tokens[this.pos];
27
+ if (this.pos < this.tokens.length)
28
+ this.pos++;
29
+ return token;
30
+ }
31
+ expect(type, context) {
32
+ const token = this.peek();
33
+ if (token.type !== type) {
34
+ throw new Error(`Expected ${type}${context ? ' ' + context : ''} but got ${token.type} ("${token.value}") at position ${token.position}`);
35
+ }
36
+ return this.advance();
37
+ }
38
+ eof() {
39
+ const last = this.tokens[this.tokens.length - 1];
40
+ return last ?? { type: TokenType.EOF, value: '', position: 0, line: 1, column: 1 };
41
+ }
42
+ isAtEnd() {
43
+ return this.peekType() === TokenType.EOF;
44
+ }
45
+ /**
46
+ * Entry point: parse a full expression.
47
+ */
48
+ parse() {
49
+ if (this.isAtEnd()) {
50
+ throw new Error('Empty expression');
51
+ }
52
+ const node = this.parseOr();
53
+ if (!this.isAtEnd()) {
54
+ const token = this.peek();
55
+ throw new Error(`Unexpected token "${token.value}" at position ${token.position} after complete expression`);
56
+ }
57
+ return node;
58
+ }
59
+ // ── Logical Operators (precedence climbing) ────────────────────────
60
+ /** Lowest precedence: or / || */
61
+ parseOr() {
62
+ let left = this.parseXor();
63
+ while (this.matchLogical('or', '||')) {
64
+ const op = this.advance();
65
+ const right = this.parseXor();
66
+ left = { kind: 'Logical', left, operator: op.value, right, position: op.position };
67
+ }
68
+ return left;
69
+ }
70
+ /** xor / ^^ */
71
+ parseXor() {
72
+ let left = this.parseAnd();
73
+ while (this.matchLogical('xor', '^^')) {
74
+ const op = this.advance();
75
+ const right = this.parseAnd();
76
+ left = { kind: 'Logical', left, operator: op.value, right, position: op.position };
77
+ }
78
+ return left;
79
+ }
80
+ /** and / && */
81
+ parseAnd() {
82
+ let left = this.parseNot();
83
+ while (this.matchLogical('and', '&&')) {
84
+ const op = this.advance();
85
+ const right = this.parseNot();
86
+ left = { kind: 'Logical', left, operator: op.value, right, position: op.position };
87
+ }
88
+ return left;
89
+ }
90
+ /** Unary not / ! */
91
+ parseNot() {
92
+ if (this.matchLogical('not', '!')) {
93
+ const op = this.advance();
94
+ // Special case: "not FIELD in {LIST}" → InExpression with negated=true
95
+ // We need to look ahead: if next is a comparison-capable thing followed by 'in'
96
+ const saved = this.pos;
97
+ try {
98
+ const operand = this.parsePrimary();
99
+ if (this.peekType() === TokenType.ComparisonOp && this.peek().value === 'in') {
100
+ this.advance(); // consume 'in'
101
+ const values = this.parseInValues();
102
+ return {
103
+ kind: 'InExpression',
104
+ field: operand,
105
+ values,
106
+ negated: true,
107
+ position: op.position,
108
+ };
109
+ }
110
+ // Not a "not X in Y" pattern — restore and parse normally
111
+ this.pos = saved;
112
+ }
113
+ catch {
114
+ this.pos = saved;
115
+ }
116
+ const operand = this.parseNot(); // right-recursive for chained not
117
+ return { kind: 'Not', operand, position: op.position };
118
+ }
119
+ return this.parseComparison();
120
+ }
121
+ // ── Comparison Expressions ─────────────────────────────────────────
122
+ parseComparison() {
123
+ const left = this.parsePrimary();
124
+ // Check for comparison operator
125
+ if (this.peekType() === TokenType.ComparisonOp) {
126
+ const op = this.advance();
127
+ // Special case: 'in' operator has special RHS syntax
128
+ if (op.value === 'in') {
129
+ const values = this.parseInValues();
130
+ return {
131
+ kind: 'InExpression',
132
+ field: left,
133
+ values,
134
+ negated: false,
135
+ position: op.position,
136
+ };
137
+ }
138
+ const right = this.parsePrimary();
139
+ return {
140
+ kind: 'Comparison',
141
+ left,
142
+ operator: op.value,
143
+ right,
144
+ position: op.position,
145
+ };
146
+ }
147
+ return left;
148
+ }
149
+ // ── In-List Values ─────────────────────────────────────────────────
150
+ parseInValues() {
151
+ // Can be: { value1 value2 ... } or $named_list
152
+ if (this.peekType() === TokenType.NamedList) {
153
+ const token = this.advance();
154
+ return [{ kind: 'NamedList', name: token.value, position: token.position }];
155
+ }
156
+ this.expect(TokenType.LeftBrace, 'after "in"');
157
+ const values = [];
158
+ while (this.peekType() !== TokenType.RightBrace && !this.isAtEnd()) {
159
+ const token = this.peek();
160
+ if (token.type === TokenType.String || token.type === TokenType.RawString) {
161
+ this.advance();
162
+ values.push({ kind: 'StringLiteral', value: token.value, position: token.position });
163
+ }
164
+ else if (token.type === TokenType.Integer) {
165
+ this.advance();
166
+ // Check for range (..)
167
+ if (this.peekType() === TokenType.DotDot) {
168
+ this.advance(); // consume ..
169
+ const end = this.expect(TokenType.Integer, 'in range');
170
+ values.push({ kind: 'IntegerLiteral', value: parseInt(token.value), position: token.position });
171
+ values.push({ kind: 'IntegerLiteral', value: parseInt(end.value), position: end.position });
172
+ }
173
+ else {
174
+ values.push({ kind: 'IntegerLiteral', value: parseInt(token.value), position: token.position });
175
+ }
176
+ }
177
+ else if (token.type === TokenType.IPAddress) {
178
+ this.advance();
179
+ // Check for CIDR /xx
180
+ if (this.peekType() === TokenType.Slash) {
181
+ this.advance(); // consume /
182
+ const bits = this.expect(TokenType.Integer, 'in CIDR');
183
+ values.push({ kind: 'IPLiteral', value: token.value, cidr: parseInt(bits.value), position: token.position });
184
+ }
185
+ else if (this.peekType() === TokenType.DotDot) {
186
+ // IP range
187
+ this.advance(); // consume ..
188
+ const endIP = this.expect(TokenType.IPAddress, 'in IP range');
189
+ values.push({ kind: 'IPLiteral', value: token.value, position: token.position });
190
+ values.push({ kind: 'IPLiteral', value: endIP.value, position: endIP.position });
191
+ }
192
+ else {
193
+ values.push({ kind: 'IPLiteral', value: token.value, position: token.position });
194
+ }
195
+ }
196
+ else {
197
+ throw new Error(`Unexpected token "${token.value}" (${token.type}) in in-list at position ${token.position}`);
198
+ }
199
+ }
200
+ this.expect(TokenType.RightBrace, 'closing in-list');
201
+ return values;
202
+ }
203
+ // ── Primary Expressions ────────────────────────────────────────────
204
+ parsePrimary() {
205
+ const token = this.peek();
206
+ switch (token.type) {
207
+ case TokenType.LeftParen:
208
+ return this.parseGroup();
209
+ case TokenType.Boolean:
210
+ this.advance();
211
+ return { kind: 'BooleanLiteral', value: token.value === 'true', position: token.position };
212
+ case TokenType.String:
213
+ case TokenType.RawString:
214
+ this.advance();
215
+ return { kind: 'StringLiteral', value: token.value, position: token.position };
216
+ case TokenType.Integer:
217
+ this.advance();
218
+ return { kind: 'IntegerLiteral', value: parseInt(token.value), position: token.position };
219
+ case TokenType.IPAddress:
220
+ this.advance();
221
+ return { kind: 'IPLiteral', value: token.value, position: token.position };
222
+ case TokenType.NamedList:
223
+ this.advance();
224
+ return { kind: 'NamedList', name: token.value, position: token.position };
225
+ case TokenType.Function:
226
+ return this.parseFunctionCall();
227
+ case TokenType.Field:
228
+ return this.parseFieldAccess();
229
+ default:
230
+ throw new Error(`Unexpected token "${token.value}" (${token.type}) at position ${token.position}`);
231
+ }
232
+ }
233
+ // ── Grouped Expression ─────────────────────────────────────────────
234
+ parseGroup() {
235
+ const open = this.expect(TokenType.LeftParen);
236
+ const expr = this.parseOr();
237
+ this.expect(TokenType.RightParen, 'to close group');
238
+ return { kind: 'Group', expression: expr, position: open.position };
239
+ }
240
+ // ── Function Call ──────────────────────────────────────────────────
241
+ parseFunctionCall() {
242
+ const nameToken = this.expect(TokenType.Function);
243
+ this.expect(TokenType.LeftParen, `after function "${nameToken.value}"`);
244
+ const args = [];
245
+ if (this.peekType() !== TokenType.RightParen) {
246
+ args.push(this.parseOr());
247
+ while (this.peekType() === TokenType.Comma) {
248
+ this.advance(); // consume comma
249
+ args.push(this.parseOr());
250
+ }
251
+ }
252
+ this.expect(TokenType.RightParen, `to close function "${nameToken.value}"`);
253
+ let result = {
254
+ kind: 'FunctionCall',
255
+ name: nameToken.value,
256
+ args,
257
+ position: nameToken.position,
258
+ };
259
+ // Handle chained array unpacks and bracket access after function call
260
+ // e.g., lower(http.request.headers.names[*])[*]
261
+ while (this.peekType() === TokenType.ArrayUnpack || this.peekType() === TokenType.LeftBracket) {
262
+ if (this.peekType() === TokenType.ArrayUnpack) {
263
+ const unpack = this.advance();
264
+ result = { kind: 'ArrayUnpack', field: result, position: unpack.position };
265
+ }
266
+ else {
267
+ // Bracket access after function result - just consume it as part of the expression
268
+ this.advance(); // [
269
+ if (this.peekType() === TokenType.String || this.peekType() === TokenType.RawString || this.peekType() === TokenType.Integer) {
270
+ this.advance(); // key/index
271
+ }
272
+ this.expect(TokenType.RightBracket);
273
+ }
274
+ }
275
+ return result;
276
+ }
277
+ // ── Field Access ───────────────────────────────────────────────────
278
+ parseFieldAccess() {
279
+ const fieldToken = this.expect(TokenType.Field);
280
+ let field = fieldToken.value;
281
+ let mapKey;
282
+ let arrayIndex;
283
+ // Handle bracket access: field["key"] or field[0]
284
+ while (this.peekType() === TokenType.LeftBracket) {
285
+ this.advance(); // consume [
286
+ const inner = this.peek();
287
+ if (inner.type === TokenType.String || inner.type === TokenType.RawString) {
288
+ mapKey = inner.value;
289
+ this.advance();
290
+ }
291
+ else if (inner.type === TokenType.Integer) {
292
+ arrayIndex = parseInt(inner.value);
293
+ this.advance();
294
+ }
295
+ this.expect(TokenType.RightBracket);
296
+ }
297
+ // Handle array unpack [*]
298
+ if (this.peekType() === TokenType.ArrayUnpack) {
299
+ const unpack = this.advance();
300
+ const fieldNode = { kind: 'FieldAccess', field, mapKey, position: fieldToken.position };
301
+ return { kind: 'ArrayUnpack', field: fieldNode, position: unpack.position };
302
+ }
303
+ return { kind: 'FieldAccess', field, mapKey, arrayIndex, position: fieldToken.position };
304
+ }
305
+ // ── Helpers ────────────────────────────────────────────────────────
306
+ matchLogical(...values) {
307
+ const token = this.peek();
308
+ return token.type === TokenType.LogicalOp && values.includes(token.value);
309
+ }
310
+ }
311
+ /**
312
+ * Parse a Cloudflare expression string into an AST.
313
+ * @throws Error on syntax errors
314
+ */
315
+ export function parse(input) {
316
+ const tokens = tokenize(input);
317
+ const parser = new Parser(tokens);
318
+ return parser.parse();
319
+ }
320
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Cloudflare expression fields registry.
3
+ *
4
+ * Reference: https://developers.cloudflare.com/ruleset-engine/rules-language/fields/reference/
5
+ *
6
+ * MAINTAINER NOTE: To add a new field, add it to the FIELDS array below.
7
+ * To deprecate a field, set `deprecated: true` and `replacement` to the new field name.
8
+ */
9
+ import type { FieldType } from './operators.js';
10
+ export interface FieldDef {
11
+ /** Full dotted field name (e.g., "http.request.uri.path") */
12
+ name: string;
13
+ /** Value type */
14
+ type: FieldType;
15
+ /** Whether this field is deprecated */
16
+ deprecated?: boolean;
17
+ /** Suggested replacement field for deprecated fields */
18
+ replacement?: string;
19
+ /** Phases where this field is available. Empty array = all phases. */
20
+ phases?: string[];
21
+ /** Human-readable notes */
22
+ notes?: string;
23
+ }
24
+ /**
25
+ * Master field registry.
26
+ *
27
+ * Phases key:
28
+ * - Empty phases array or undefined = available in all phases
29
+ * - Specific phase names = only available in those phases
30
+ *
31
+ * Response fields are only available in response phases.
32
+ */
33
+ export declare const FIELDS: FieldDef[];
34
+ /**
35
+ * Look up a field by name.
36
+ * Returns undefined if the field is not recognized.
37
+ */
38
+ export declare function findField(name: string): FieldDef | undefined;
39
+ /**
40
+ * Check if a field name could be a dynamic map/array access.
41
+ * E.g., "http.request.headers" is a Map field, so "http.request.headers["host"]" is valid.
42
+ * Returns the base field if found.
43
+ */
44
+ export declare function findBaseField(name: string): FieldDef | undefined;