@birdcc/parser 0.0.1-alpha.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.
Files changed (76) hide show
  1. package/.oxfmtrc.json +16 -0
  2. package/LICENSE +674 -0
  3. package/README.md +312 -0
  4. package/dist/declarations/basic.d.ts +9 -0
  5. package/dist/declarations/basic.d.ts.map +1 -0
  6. package/dist/declarations/basic.js +180 -0
  7. package/dist/declarations/basic.js.map +1 -0
  8. package/dist/declarations/filter.d.ts +6 -0
  9. package/dist/declarations/filter.d.ts.map +1 -0
  10. package/dist/declarations/filter.js +330 -0
  11. package/dist/declarations/filter.js.map +1 -0
  12. package/dist/declarations/parse-declarations.d.ts +4 -0
  13. package/dist/declarations/parse-declarations.d.ts.map +1 -0
  14. package/dist/declarations/parse-declarations.js +54 -0
  15. package/dist/declarations/parse-declarations.js.map +1 -0
  16. package/dist/declarations/protocol.d.ts +6 -0
  17. package/dist/declarations/protocol.d.ts.map +1 -0
  18. package/dist/declarations/protocol.js +444 -0
  19. package/dist/declarations/protocol.js.map +1 -0
  20. package/dist/declarations/shared.d.ts +56 -0
  21. package/dist/declarations/shared.d.ts.map +1 -0
  22. package/dist/declarations/shared.js +169 -0
  23. package/dist/declarations/shared.js.map +1 -0
  24. package/dist/declarations/top-level.d.ts +6 -0
  25. package/dist/declarations/top-level.d.ts.map +1 -0
  26. package/dist/declarations/top-level.js +141 -0
  27. package/dist/declarations/top-level.js.map +1 -0
  28. package/dist/declarations.d.ts +2 -0
  29. package/dist/declarations.d.ts.map +1 -0
  30. package/dist/declarations.js +2 -0
  31. package/dist/declarations.js.map +1 -0
  32. package/dist/index.d.ts +8 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +49 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/issues.d.ts +9 -0
  37. package/dist/issues.d.ts.map +1 -0
  38. package/dist/issues.js +119 -0
  39. package/dist/issues.js.map +1 -0
  40. package/dist/runtime.d.ts +5 -0
  41. package/dist/runtime.d.ts.map +1 -0
  42. package/dist/runtime.js +51 -0
  43. package/dist/runtime.js.map +1 -0
  44. package/dist/tree-sitter-birdcc.wasm +0 -0
  45. package/dist/tree.d.ts +16 -0
  46. package/dist/tree.d.ts.map +1 -0
  47. package/dist/tree.js +150 -0
  48. package/dist/tree.js.map +1 -0
  49. package/dist/types.d.ts +222 -0
  50. package/dist/types.d.ts.map +1 -0
  51. package/dist/types.js +2 -0
  52. package/dist/types.js.map +1 -0
  53. package/grammar.js +601 -0
  54. package/package.json +46 -0
  55. package/scripts/sync-wasm-paths.mjs +21 -0
  56. package/src/declarations/basic.ts +272 -0
  57. package/src/declarations/filter.ts +437 -0
  58. package/src/declarations/parse-declarations.ts +84 -0
  59. package/src/declarations/protocol.ts +597 -0
  60. package/src/declarations/shared.ts +275 -0
  61. package/src/declarations/top-level.ts +185 -0
  62. package/src/declarations.ts +1 -0
  63. package/src/index.ts +102 -0
  64. package/src/issues.ts +154 -0
  65. package/src/runtime.ts +64 -0
  66. package/src/tree-sitter-birdcc.wasm +0 -0
  67. package/src/tree.ts +210 -0
  68. package/src/types.ts +329 -0
  69. package/test/fixtures.test.ts +48 -0
  70. package/test/ip-literal-candidate.test.ts +39 -0
  71. package/test/parser.test.ts +475 -0
  72. package/test/realworld-smoke.test.ts +46 -0
  73. package/test/runtime.test.ts +51 -0
  74. package/test/tree.test.ts +83 -0
  75. package/tree-sitter.json +37 -0
  76. package/tsconfig.json +8 -0
package/README.md ADDED
@@ -0,0 +1,312 @@
1
+ <div align="center">
2
+
3
+ # 🕊 BIRD Config Parser (@birdcc/parser)
4
+
5
+ </div>
6
+
7
+ [![npm version](https://img.shields.io/badge/version-0.1.0--alpha-blue)](https://www.npmjs.com/package/@birdcc/parser) [![License: GPL-3.0](https://img.shields.io/badge/License-GPL--3.0--only-green.svg)](https://www.gnu.org/licenses/gpl-3.0) [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-3178c6?logo=typescript)](https://www.typescriptlang.org/) [![Tree-sitter](https://img.shields.io/badge/Tree--sitter-powered-9f5ec2)](https://tree-sitter.github.io/)
8
+
9
+ > [Overview](#overview) · [Features](#features) · [Installation](#installation) · [Usage](#usage) · [API Reference](#api-reference) · [Building](#building)
10
+
11
+ ## Overview
12
+
13
+ **@birdcc/parser** is a Tree-sitter based parser for BIRD2 configuration files, delivering high-performance syntax analysis and declaration extraction capabilities.
14
+
15
+ ### Core Highlights
16
+
17
+ | Feature | Description |
18
+ | ------------------------- | --------------------------------------------------------------------------------- |
19
+ | 🌲 Tree-sitter Grammar | Complete BIRD2 grammar definition with error recovery support |
20
+ | ⚡ WASM Runtime | WebAssembly runtime powered by `web-tree-sitter` for cross-platform compatibility |
21
+ | 🔌 Async API | Asynchronous parsing interface optimized for server and CLI environments |
22
+ | 📦 Declaration Extraction | Extract top-level declarations and protocol statements for semantic analysis |
23
+ | 🩺 Error Diagnostics | Automatic syntax error detection with precise source location information |
24
+
25
+ ---
26
+
27
+ ## Features
28
+
29
+ ### Declaration Extraction
30
+
31
+ - **`include`** — File inclusion statements
32
+ - **`define`** — Macro definitions
33
+ - **`router id`** — Router identifier configuration
34
+ - **`table`** — Routing table definitions (ipv4/ipv6/vpn4/vpn6/roa4/roa6/flow4/flow6)
35
+
36
+ ### Protocols & Templates
37
+
38
+ - **`protocol`** — Protocol definitions supporting types like bgp/ospf/static/direct
39
+ - **`template`** — Protocol template definitions
40
+ - **Template Inheritance** — Support for template inheritance via the `from` clause
41
+
42
+ ### Protocol Statements
43
+
44
+ - **`local as`** — Local AS number configuration
45
+ - **`neighbor ... as ...`** — BGP neighbor definition
46
+ - **`import`** — Import rules (all/none/filter/where)
47
+ - **`export`** — Export rules (all/none/filter/where)
48
+
49
+ ### Channel Statements
50
+
51
+ - **Types** — ipv4/ipv6/vpn4/vpn6/roa4/roa6/flow4/flow6/mpls
52
+ - **`table`** — Associated routing table
53
+ - **`import/export`** — Channel-level import/export rules
54
+ - **`import limit` / `receive limit`** — Route limit configuration
55
+ - **`debug`** — Debug configuration
56
+ - **`import keep filtered`** — Retain filtered routes
57
+
58
+ ### Filter & Function Skeleton
59
+
60
+ - **Control Flow** — `if` / `case` conditional statements
61
+ - **Actions** — `accept` / `reject` / `return` routing decisions
62
+ - **Literal Extraction** — `ip` / `prefix` literals for semantic validation
63
+ - **Match Expressions** — Pattern matching with the `~` operator
64
+
65
+ ### Error Diagnostics
66
+
67
+ - **ERROR Nodes** — Tree-sitter syntax errors with complete source ranges
68
+ - **MISSING Nodes** — Missing symbol detection (e.g., missing semicolons)
69
+ - **Brace Balancing** — Automatic detection of unbalanced braces
70
+
71
+ ---
72
+
73
+ ## Installation
74
+
75
+ ```bash
76
+ # Using pnpm (recommended)
77
+ pnpm add @birdcc/parser
78
+
79
+ # Using npm
80
+ npm install @birdcc/parser
81
+
82
+ # Using yarn
83
+ yarn add @birdcc/parser
84
+ ```
85
+
86
+ ### Prerequisites
87
+
88
+ - Node.js >= 18
89
+ - TypeScript >= 5.0 (if using TypeScript)
90
+
91
+ ---
92
+
93
+ ## Usage
94
+
95
+ ### Basic Parsing
96
+
97
+ ```typescript
98
+ import { parseBirdConfig } from "@birdcc/parser";
99
+
100
+ const source = `
101
+ protocol bgp edge {
102
+ local as 65001;
103
+ neighbor 192.0.2.1 as 65002;
104
+ import all;
105
+ export filter policy_out;
106
+
107
+ ipv4 {
108
+ table bgp_v4;
109
+ import limit 1000 action restart;
110
+ };
111
+ }
112
+ `;
113
+
114
+ const result = await parseBirdConfig(source);
115
+
116
+ // View extracted declarations
117
+ console.log(result.program.declarations);
118
+
119
+ // View diagnostic issues
120
+ console.log(result.issues);
121
+ ```
122
+
123
+ ### Handling Errors
124
+
125
+ ```typescript
126
+ import { parseBirdConfig } from "@birdcc/parser";
127
+
128
+ const result = await parseBirdConfig(source);
129
+
130
+ if (result.issues.length > 0) {
131
+ for (const issue of result.issues) {
132
+ console.error(
133
+ `[${issue.code}] Line ${issue.line}:${issue.column} - ${issue.message}`,
134
+ );
135
+ }
136
+ }
137
+
138
+ // Even with errors, the result contains processable declarations
139
+ console.log(`Found ${result.program.declarations.length} declarations`);
140
+ ```
141
+
142
+ ### Extract Protocol Details
143
+
144
+ ```typescript
145
+ import { parseBirdConfig } from "@birdcc/parser";
146
+
147
+ const result = await parseBirdConfig(source);
148
+
149
+ for (const decl of result.program.declarations) {
150
+ if (decl.kind === "protocol") {
151
+ console.log(`Protocol: ${decl.name} (${decl.protocolType})`);
152
+
153
+ for (const stmt of decl.statements) {
154
+ if (stmt.kind === "local-as") {
155
+ console.log(` Local AS: ${stmt.asn}`);
156
+ }
157
+ if (stmt.kind === "neighbor") {
158
+ console.log(` Neighbor: ${stmt.address} AS ${stmt.asn}`);
159
+ }
160
+ }
161
+ }
162
+ }
163
+ ```
164
+
165
+ ---
166
+
167
+ ## API Reference
168
+
169
+ ### Main Function
170
+
171
+ ```typescript
172
+ function parseBirdConfig(input: string): Promise<ParsedBirdDocument>;
173
+ ```
174
+
175
+ Parses BIRD configuration content and returns the parsing result along with diagnostic information.
176
+
177
+ **Parameters:**
178
+
179
+ - `input: string` — Configuration file content
180
+
181
+ **Returns:** `Promise<ParsedBirdDocument>` — Parsing result object
182
+
183
+ ### Core Types
184
+
185
+ #### `ParsedBirdDocument`
186
+
187
+ ```typescript
188
+ interface ParsedBirdDocument {
189
+ program: BirdProgram; // Parsed program structure
190
+ issues: ParseIssue[]; // Diagnostic issues
191
+ }
192
+ ```
193
+
194
+ #### `BirdDeclaration`
195
+
196
+ Union type of declaration kinds:
197
+
198
+ | Type | Description |
199
+ | --------------------- | --------------------------- |
200
+ | `IncludeDeclaration` | `include "file.conf";` |
201
+ | `DefineDeclaration` | `define MACRO = value;` |
202
+ | `RouterIdDeclaration` | `router id 192.0.2.1;` |
203
+ | `TableDeclaration` | `table bgp_v4;` |
204
+ | `ProtocolDeclaration` | `protocol bgp name { ... }` |
205
+ | `TemplateDeclaration` | `template bgp base { ... }` |
206
+ | `FilterDeclaration` | `filter name { ... }` |
207
+ | `FunctionDeclaration` | `function name() { ... }` |
208
+
209
+ #### `ParseIssue`
210
+
211
+ ```typescript
212
+ interface ParseIssue {
213
+ code:
214
+ | "syntax/missing-semicolon"
215
+ | "syntax/unbalanced-brace"
216
+ | "parser/missing-symbol"
217
+ | "parser/syntax-error"
218
+ | "parser/runtime-error";
219
+ message: string;
220
+ line: number; // Start line (1-based)
221
+ column: number; // Start column (1-based)
222
+ endLine: number; // End line
223
+ endColumn: number; // End column
224
+ }
225
+ ```
226
+
227
+ ---
228
+
229
+ ## Building
230
+
231
+ ### Development Build
232
+
233
+ ```bash
234
+ # Install dependencies
235
+ pnpm install
236
+
237
+ # Build TypeScript
238
+ pnpm --filter @birdcc/parser run build
239
+
240
+ # Run tests
241
+ pnpm --filter @birdcc/parser run test
242
+
243
+ # Type check
244
+ pnpm --filter @birdcc/parser run typecheck
245
+ ```
246
+
247
+ ### WASM Build
248
+
249
+ ```bash
250
+ # Regenerate grammar files
251
+ pnpm --filter @birdcc/parser run build:grammar
252
+
253
+ # Build WASM runtime (requires Emscripten or Docker)
254
+ pnpm --filter @birdcc/parser run build:wasm
255
+ ```
256
+
257
+ ### File Structure
258
+
259
+ **Tracked Files (in Git):**
260
+
261
+ | File | Description |
262
+ | ----------------------------- | ------------------------------ |
263
+ | `grammar.js` | Tree-sitter grammar definition |
264
+ | `src/tree-sitter-birdcc.wasm` | WASM runtime binary |
265
+ | `src/*.ts` | TypeScript source files |
266
+
267
+ **Generated Files (not tracked):**
268
+
269
+ | File | Description |
270
+ | --------------------- | --------------------- |
271
+ | `src/parser.c` | Generated C parser |
272
+ | `src/grammar.json` | Serialized grammar |
273
+ | `src/node-types.json` | Node type definitions |
274
+
275
+ ---
276
+
277
+ ## Related Packages
278
+
279
+ | Package | Description |
280
+ | ------------------------------------------ | --------------------------------------- |
281
+ | [@birdcc/core](../@birdcc/core/) | AST, symbol table, and type checker |
282
+ | [@birdcc/linter](../@birdcc/linter/) | 32+ lint rules and diagnostics |
283
+ | [@birdcc/lsp](../@birdcc/lsp/) | Language Server Protocol implementation |
284
+ | [@birdcc/formatter](../@birdcc/formatter/) | Code formatter |
285
+ | [@birdcc/cli](../@birdcc/cli/) | Command-line interface |
286
+
287
+ ---
288
+
289
+ ### 📖 Documentation
290
+
291
+ - [BIRD Official Documentation](https://bird.network.cz/)
292
+ - [BIRD2 User Manual](https://bird.network.cz/doc/bird.html)
293
+ - [Extension Configuration Guide](./docs/configuration.md)
294
+ - [GitHub Project](https://github.com/bird-chinese-community/BIRD-LSP)
295
+
296
+ ---
297
+
298
+ ## 📝 License
299
+
300
+ This project is licensed under the [GPL-3.0 License](https://github.com/bird-chinese-community/BIRD-LSP/blob/main/LICENSE).
301
+
302
+ ---
303
+
304
+ <p align="center">
305
+ <sub>Built with ❤️ by the BIRD Chinese Community (BIRDCC)</sub>
306
+ </p>
307
+
308
+ <p align="center">
309
+ <a href="https://github.com/bird-chinese-community/BIRD-LSP">🕊 GitHub</a> ·
310
+ <a href="https://marketplace.visualstudio.com/items?itemName=birdcc.bird2-lsp">🛒 Marketplace</a> ·
311
+ <a href="https://github.com/bird-chinese-community/BIRD-LSP/issues">🐛 Report Issues</a>
312
+ </p>
@@ -0,0 +1,9 @@
1
+ import type { Node as SyntaxNode } from "web-tree-sitter";
2
+ import type { ParseIssue } from "../types.js";
3
+ import { type DefineDeclaration, type IncludeDeclaration, type RouterIdDeclaration, type TableDeclaration, type TemplateDeclaration } from "./shared.js";
4
+ export declare const parseIncludeDeclaration: (declarationNode: SyntaxNode, source: string, issues: ParseIssue[]) => IncludeDeclaration;
5
+ export declare const parseDefineDeclaration: (declarationNode: SyntaxNode, source: string, issues: ParseIssue[]) => DefineDeclaration;
6
+ export declare const parseRouterIdDeclaration: (declarationNode: SyntaxNode, source: string, issues: ParseIssue[]) => RouterIdDeclaration;
7
+ export declare const parseTableDeclaration: (declarationNode: SyntaxNode, source: string, issues: ParseIssue[]) => TableDeclaration;
8
+ export declare const parseTemplateDeclaration: (declarationNode: SyntaxNode, source: string, issues: ParseIssue[]) => TemplateDeclaration;
9
+ //# sourceMappingURL=basic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"basic.d.ts","sourceRoot":"","sources":["../../src/declarations/basic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EAIzB,MAAM,aAAa,CAAC;AAErB,eAAO,MAAM,uBAAuB,GAClC,iBAAiB,UAAU,EAC3B,QAAQ,MAAM,EACd,QAAQ,UAAU,EAAE,KACnB,kBAoBF,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,iBAAiB,UAAU,EAC3B,QAAQ,MAAM,EACd,QAAQ,UAAU,EAAE,KACnB,iBAoBF,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,iBAAiB,UAAU,EAC3B,QAAQ,MAAM,EACd,QAAQ,UAAU,EAAE,KACnB,mBA6EF,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,iBAAiB,UAAU,EAC3B,QAAQ,MAAM,EACd,QAAQ,UAAU,EAAE,KACnB,gBAsCF,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,iBAAiB,UAAU,EAC3B,QAAQ,MAAM,EACd,QAAQ,UAAU,EAAE,KACnB,mBAyEF,CAAC"}
@@ -0,0 +1,180 @@
1
+ import { pushMissingFieldIssue } from "../issues.js";
2
+ import { isPresentNode, stripQuotes, textOf, toRange } from "../tree.js";
3
+ import { isStrictIpv4Literal, nodeOrSelf, normalizeTableType, } from "./shared.js";
4
+ export const parseIncludeDeclaration = (declarationNode, source, issues) => {
5
+ const declarationRange = toRange(declarationNode, source);
6
+ const pathNode = declarationNode.childForFieldName("path");
7
+ if (!isPresentNode(pathNode)) {
8
+ pushMissingFieldIssue(issues, declarationNode, "Missing path for include declaration", source);
9
+ }
10
+ return {
11
+ kind: "include",
12
+ path: isPresentNode(pathNode) ? stripQuotes(textOf(pathNode, source)) : "",
13
+ pathRange: isPresentNode(pathNode)
14
+ ? toRange(pathNode, source)
15
+ : declarationRange,
16
+ ...declarationRange,
17
+ };
18
+ };
19
+ export const parseDefineDeclaration = (declarationNode, source, issues) => {
20
+ const declarationRange = toRange(declarationNode, source);
21
+ const nameNode = declarationNode.childForFieldName("name");
22
+ if (!isPresentNode(nameNode)) {
23
+ pushMissingFieldIssue(issues, declarationNode, "Missing name for define declaration", source);
24
+ }
25
+ return {
26
+ kind: "define",
27
+ name: isPresentNode(nameNode) ? textOf(nameNode, source) : "",
28
+ nameRange: isPresentNode(nameNode)
29
+ ? toRange(nameNode, source)
30
+ : declarationRange,
31
+ ...declarationRange,
32
+ };
33
+ };
34
+ export const parseRouterIdDeclaration = (declarationNode, source, issues) => {
35
+ const declarationRange = toRange(declarationNode, source);
36
+ const rawValueNode = declarationNode.childForFieldName("value");
37
+ if (!isPresentNode(rawValueNode)) {
38
+ pushMissingFieldIssue(issues, declarationNode, "Missing value for router id declaration", source);
39
+ return {
40
+ kind: "router-id",
41
+ value: "",
42
+ valueKind: "unknown",
43
+ valueRange: declarationRange,
44
+ ...declarationRange,
45
+ };
46
+ }
47
+ const valueNode = nodeOrSelf(rawValueNode);
48
+ if (valueNode.type === "router_id_from_clause") {
49
+ const fromSourceNode = valueNode.childForFieldName("from_source");
50
+ const fromSourceText = isPresentNode(fromSourceNode)
51
+ ? textOf(fromSourceNode, source).toLowerCase()
52
+ : "";
53
+ if (fromSourceText !== "routing" && fromSourceText !== "dynamic") {
54
+ return {
55
+ kind: "router-id",
56
+ value: textOf(valueNode, source),
57
+ valueKind: "unknown",
58
+ valueRange: toRange(valueNode, source),
59
+ ...declarationRange,
60
+ };
61
+ }
62
+ return {
63
+ kind: "router-id",
64
+ value: textOf(valueNode, source),
65
+ valueKind: "from",
66
+ valueRange: toRange(valueNode, source),
67
+ fromSource: fromSourceText,
68
+ ...declarationRange,
69
+ };
70
+ }
71
+ if (valueNode.type === "ipv4_literal" &&
72
+ isStrictIpv4Literal(textOf(valueNode, source))) {
73
+ return {
74
+ kind: "router-id",
75
+ value: textOf(valueNode, source),
76
+ valueKind: "ip",
77
+ valueRange: toRange(valueNode, source),
78
+ ...declarationRange,
79
+ };
80
+ }
81
+ if (valueNode.type === "number") {
82
+ return {
83
+ kind: "router-id",
84
+ value: textOf(valueNode, source),
85
+ valueKind: "number",
86
+ valueRange: toRange(valueNode, source),
87
+ ...declarationRange,
88
+ };
89
+ }
90
+ return {
91
+ kind: "router-id",
92
+ value: textOf(valueNode, source),
93
+ valueKind: "unknown",
94
+ valueRange: toRange(valueNode, source),
95
+ ...declarationRange,
96
+ };
97
+ };
98
+ export const parseTableDeclaration = (declarationNode, source, issues) => {
99
+ const declarationRange = toRange(declarationNode, source);
100
+ const tableTypeNode = declarationNode.childForFieldName("table_type");
101
+ const nameNode = declarationNode.childForFieldName("name");
102
+ const attrsNode = declarationNode.childForFieldName("attrs");
103
+ if (!isPresentNode(nameNode)) {
104
+ pushMissingFieldIssue(issues, declarationNode, "Missing name for table declaration", source);
105
+ }
106
+ const firstToken = declarationNode.children[0];
107
+ const tableTypeText = isPresentNode(tableTypeNode)
108
+ ? textOf(tableTypeNode, source)
109
+ : firstToken
110
+ ? textOf(firstToken, source)
111
+ : "unknown";
112
+ return {
113
+ kind: "table",
114
+ tableType: normalizeTableType(tableTypeText),
115
+ tableTypeRange: isPresentNode(tableTypeNode)
116
+ ? toRange(tableTypeNode, source)
117
+ : declarationRange,
118
+ name: isPresentNode(nameNode) ? textOf(nameNode, source) : "",
119
+ nameRange: isPresentNode(nameNode)
120
+ ? toRange(nameNode, source)
121
+ : declarationRange,
122
+ attrsText: isPresentNode(attrsNode) ? textOf(attrsNode, source) : undefined,
123
+ attrsRange: isPresentNode(attrsNode)
124
+ ? toRange(attrsNode, source)
125
+ : undefined,
126
+ ...declarationRange,
127
+ };
128
+ };
129
+ export const parseTemplateDeclaration = (declarationNode, source, issues) => {
130
+ const declarationRange = toRange(declarationNode, source);
131
+ const declarationText = textOf(declarationNode, source);
132
+ const declarationHeader = declarationText.split("{", 1)[0] ?? declarationText;
133
+ const templateTypeNode = declarationNode.childForFieldName("template_type");
134
+ const nameNode = declarationNode.childForFieldName("name");
135
+ const fromTemplateNode = declarationNode.childForFieldName("from_template");
136
+ const bodyNode = declarationNode.childForFieldName("body");
137
+ const inferredFromTemplateMatch = declarationHeader.match(/\bfrom\s+([A-Za-z_][A-Za-z0-9_-]*)\b/i);
138
+ const inferredFromTemplate = inferredFromTemplateMatch?.[1];
139
+ const hasFromKeyword = declarationNode.children.some((entry) => entry.type === "from") ||
140
+ /\bfrom\b/i.test(declarationHeader);
141
+ if (!isPresentNode(templateTypeNode)) {
142
+ pushMissingFieldIssue(issues, declarationNode, "Missing template type for template declaration", source);
143
+ }
144
+ if (!isPresentNode(nameNode)) {
145
+ pushMissingFieldIssue(issues, declarationNode, "Missing name for template declaration", source);
146
+ }
147
+ if (hasFromKeyword && !isPresentNode(fromTemplateNode)) {
148
+ pushMissingFieldIssue(issues, declarationNode, "Missing template name after from clause", source);
149
+ }
150
+ if (!isPresentNode(bodyNode)) {
151
+ issues.push({
152
+ code: "syntax/unbalanced-brace",
153
+ message: "Missing '{' for template declaration",
154
+ ...declarationRange,
155
+ });
156
+ }
157
+ return {
158
+ kind: "template",
159
+ templateType: isPresentNode(templateTypeNode)
160
+ ? textOf(templateTypeNode, source)
161
+ : "",
162
+ templateTypeRange: isPresentNode(templateTypeNode)
163
+ ? toRange(templateTypeNode, source)
164
+ : declarationRange,
165
+ name: isPresentNode(nameNode) ? textOf(nameNode, source) : "",
166
+ nameRange: isPresentNode(nameNode)
167
+ ? toRange(nameNode, source)
168
+ : declarationRange,
169
+ fromTemplate: isPresentNode(fromTemplateNode)
170
+ ? textOf(fromTemplateNode, source)
171
+ : inferredFromTemplate,
172
+ fromTemplateRange: isPresentNode(fromTemplateNode)
173
+ ? toRange(fromTemplateNode, source)
174
+ : inferredFromTemplate
175
+ ? declarationRange
176
+ : undefined,
177
+ ...declarationRange,
178
+ };
179
+ };
180
+ //# sourceMappingURL=basic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"basic.js","sourceRoot":"","sources":["../../src/declarations/basic.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { Node as SyntaxNode } from "web-tree-sitter";
2
+ import type { ParseIssue } from "../types.js";
3
+ import { type FilterDeclaration, type FunctionDeclaration } from "./shared.js";
4
+ export declare const parseFilterDeclaration: (declarationNode: SyntaxNode, source: string, issues: ParseIssue[]) => FilterDeclaration;
5
+ export declare const parseFunctionDeclaration: (declarationNode: SyntaxNode, source: string, issues: ParseIssue[]) => FunctionDeclaration;
6
+ //# sourceMappingURL=filter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../src/declarations/filter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,KAAK,EAAuB,UAAU,EAAE,MAAM,aAAa,CAAC;AAGnE,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EAGzB,MAAM,aAAa,CAAC;AAkVrB,eAAO,MAAM,sBAAsB,GACjC,iBAAiB,UAAU,EAC3B,QAAQ,MAAM,EACd,QAAQ,UAAU,EAAE,KACnB,iBAuCF,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,iBAAiB,UAAU,EAC3B,QAAQ,MAAM,EACd,QAAQ,UAAU,EAAE,KACnB,mBAuCF,CAAC"}