@semanticintent/recall 0.2.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/README.md +279 -0
- package/bin/recall.js +2 -0
- package/dist/cli/commands/check.d.ts +3 -0
- package/dist/cli/commands/check.d.ts.map +1 -0
- package/dist/cli/commands/check.js +20 -0
- package/dist/cli/commands/check.js.map +1 -0
- package/dist/cli/commands/compile.d.ts +3 -0
- package/dist/cli/commands/compile.d.ts.map +1 -0
- package/dist/cli/commands/compile.js +21 -0
- package/dist/cli/commands/compile.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +12 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/compiler/index.d.ts +14 -0
- package/dist/compiler/index.d.ts.map +1 -0
- package/dist/compiler/index.js +115 -0
- package/dist/compiler/index.js.map +1 -0
- package/dist/generator/html.d.ts +4 -0
- package/dist/generator/html.d.ts.map +1 -0
- package/dist/generator/html.js +353 -0
- package/dist/generator/html.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/parser/rcl.d.ts +56 -0
- package/dist/parser/rcl.d.ts.map +1 -0
- package/dist/parser/rcl.js +353 -0
- package/dist/parser/rcl.js.map +1 -0
- package/package.json +43 -0
- package/tsconfig.json +17 -0
package/README.md
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# RECALL
|
|
2
|
+
|
|
3
|
+
**A declarative web interface language with COBOL-inspired syntax.**
|
|
4
|
+
|
|
5
|
+
```cobol
|
|
6
|
+
IDENTIFICATION DIVISION.
|
|
7
|
+
PROGRAM-ID. MY-SITE.
|
|
8
|
+
PAGE-TITLE. "Hello, World.".
|
|
9
|
+
|
|
10
|
+
DATA DIVISION.
|
|
11
|
+
WORKING-STORAGE SECTION.
|
|
12
|
+
01 HERO-HEAD PIC X(40) VALUE "STILL HERE.".
|
|
13
|
+
01 HERO-BODY PIC X(200) VALUE "Built to last.".
|
|
14
|
+
|
|
15
|
+
PROCEDURE DIVISION.
|
|
16
|
+
|
|
17
|
+
RENDER-HERO.
|
|
18
|
+
DISPLAY SECTION ID "hero"
|
|
19
|
+
WITH LAYOUT CENTERED
|
|
20
|
+
WITH PADDING LARGE.
|
|
21
|
+
DISPLAY HEADING-1 HERO-HEAD.
|
|
22
|
+
DISPLAY PARAGRAPH HERO-BODY.
|
|
23
|
+
STOP SECTION.
|
|
24
|
+
|
|
25
|
+
STOP RUN.
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
recall compile my-site.rcl
|
|
30
|
+
# → my-site.html (self-contained, zero dependencies)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## What is RECALL?
|
|
36
|
+
|
|
37
|
+
RECALL is a compiler, not a runtime. You write `.rcl` source files in a
|
|
38
|
+
COBOL-inspired, division-based syntax. The compiler produces a single,
|
|
39
|
+
self-contained HTML file — inline CSS, no external dependencies, no build
|
|
40
|
+
step to run the result.
|
|
41
|
+
|
|
42
|
+
The guiding principle: **the source is the artifact.**
|
|
43
|
+
|
|
44
|
+
Every compiled `.html` file embeds its original `.rcl` source in an HTML
|
|
45
|
+
comment block at the top of the output. View source on any RECALL page and
|
|
46
|
+
you see COBOL divisions.
|
|
47
|
+
|
|
48
|
+
RECALL is not:
|
|
49
|
+
- A COBOL runtime or interpreter
|
|
50
|
+
- A wrapper around React, Vue, or any JS framework
|
|
51
|
+
- A templating engine on top of HTML
|
|
52
|
+
- A joke
|
|
53
|
+
|
|
54
|
+
RECALL is:
|
|
55
|
+
- A domain-specific language for web interfaces
|
|
56
|
+
- Inspired by COBOL syntax — verbose, English-like, division-based
|
|
57
|
+
- A transpiler that produces vanilla HTML + inline CSS
|
|
58
|
+
- A statement about longevity
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Install
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
npm install -g @semanticintent/recall
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Or use it as a library:
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
npm install @semanticintent/recall
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## CLI
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
# Compile a .rcl file to HTML
|
|
80
|
+
recall compile my-site.rcl
|
|
81
|
+
|
|
82
|
+
# Compile to a specific output directory
|
|
83
|
+
recall compile my-site.rcl --out dist/
|
|
84
|
+
|
|
85
|
+
# Check a file for errors without compiling
|
|
86
|
+
recall check my-site.rcl
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Language Structure
|
|
92
|
+
|
|
93
|
+
Every RECALL program has four divisions:
|
|
94
|
+
|
|
95
|
+
```cobol
|
|
96
|
+
IDENTIFICATION DIVISION. ← who this is
|
|
97
|
+
ENVIRONMENT DIVISION. ← how it looks (theme, fonts, palette)
|
|
98
|
+
DATA DIVISION. ← what it holds (variables, lists)
|
|
99
|
+
PROCEDURE DIVISION. ← what it renders
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### IDENTIFICATION DIVISION
|
|
103
|
+
|
|
104
|
+
```cobol
|
|
105
|
+
IDENTIFICATION DIVISION.
|
|
106
|
+
PROGRAM-ID. MY-SITE.
|
|
107
|
+
AUTHOR. SEMANTICINTENT.
|
|
108
|
+
DATE-WRITTEN. 2026-04-03.
|
|
109
|
+
PAGE-TITLE. "My Site".
|
|
110
|
+
DESCRIPTION. "A site about things.".
|
|
111
|
+
FAVICON. "/favicon.ico".
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### ENVIRONMENT DIVISION
|
|
115
|
+
|
|
116
|
+
```cobol
|
|
117
|
+
ENVIRONMENT DIVISION.
|
|
118
|
+
CONFIGURATION SECTION.
|
|
119
|
+
VIEWPORT RESPONSIVE.
|
|
120
|
+
COLOR-MODE DARK.
|
|
121
|
+
FONT-PRIMARY "IBM Plex Mono".
|
|
122
|
+
FONT-SECONDARY "IBM Plex Sans".
|
|
123
|
+
|
|
124
|
+
PALETTE SECTION.
|
|
125
|
+
01 COLOR-ACCENT PIC X(7) VALUE "#00FF41".
|
|
126
|
+
01 COLOR-BG PIC X(7) VALUE "#080808".
|
|
127
|
+
01 COLOR-TEXT PIC X(7) VALUE "#E0E0E0".
|
|
128
|
+
01 COLOR-MUTED PIC X(7) VALUE "#555555".
|
|
129
|
+
01 COLOR-BORDER PIC X(7) VALUE "#1A1A1A".
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### DATA DIVISION
|
|
133
|
+
|
|
134
|
+
```cobol
|
|
135
|
+
DATA DIVISION.
|
|
136
|
+
WORKING-STORAGE SECTION.
|
|
137
|
+
01 PAGE-HEADING PIC X(60) VALUE "Hello, World.".
|
|
138
|
+
01 PAGE-BODY PIC X(200) VALUE "Welcome to RECALL.".
|
|
139
|
+
|
|
140
|
+
ITEMS SECTION.
|
|
141
|
+
01 NAV-ITEMS.
|
|
142
|
+
05 NAV-ITEM-1 PIC X(20) VALUE "HOME".
|
|
143
|
+
05 NAV-ITEM-1-HREF PIC X(80) VALUE "/".
|
|
144
|
+
05 NAV-ITEM-2 PIC X(20) VALUE "ABOUT".
|
|
145
|
+
05 NAV-ITEM-2-HREF PIC X(80) VALUE "/about".
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### PROCEDURE DIVISION
|
|
149
|
+
|
|
150
|
+
```cobol
|
|
151
|
+
PROCEDURE DIVISION.
|
|
152
|
+
|
|
153
|
+
RENDER-NAV.
|
|
154
|
+
DISPLAY NAVIGATION USING NAV-ITEMS
|
|
155
|
+
WITH STICKY YES
|
|
156
|
+
WITH LOGO "MY SITE".
|
|
157
|
+
|
|
158
|
+
RENDER-HERO.
|
|
159
|
+
DISPLAY SECTION ID "hero"
|
|
160
|
+
WITH LAYOUT CENTERED
|
|
161
|
+
WITH PADDING LARGE.
|
|
162
|
+
DISPLAY HEADING-1 PAGE-HEADING
|
|
163
|
+
WITH STYLE MONO.
|
|
164
|
+
DISPLAY PARAGRAPH PAGE-BODY.
|
|
165
|
+
DISPLAY BUTTON "Get Started"
|
|
166
|
+
ON-CLICK GOTO "#install"
|
|
167
|
+
WITH STYLE PRIMARY.
|
|
168
|
+
STOP SECTION.
|
|
169
|
+
|
|
170
|
+
STOP RUN.
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Elements
|
|
176
|
+
|
|
177
|
+
| Element | Description |
|
|
178
|
+
|---|---|
|
|
179
|
+
| `HEADING-1` / `HEADING-2` / `HEADING-3` | Section headings |
|
|
180
|
+
| `PARAGRAPH` | Body text |
|
|
181
|
+
| `LABEL` | Small uppercase label |
|
|
182
|
+
| `BUTTON` | CTA button with `ON-CLICK GOTO` |
|
|
183
|
+
| `LINK` | Inline hyperlink |
|
|
184
|
+
| `CODE-BLOCK` | Preformatted code block |
|
|
185
|
+
| `CARD-LIST` | Grid of cards from a data group |
|
|
186
|
+
| `NAVIGATION` | Site navigation with logo + links |
|
|
187
|
+
| `SECTION` | Layout container (`CENTERED`, `STACK`, `GRID`) |
|
|
188
|
+
| `FOOTER` | Page footer |
|
|
189
|
+
| `DIVIDER` | Horizontal rule |
|
|
190
|
+
| `BANNER` | Full-width announcement strip |
|
|
191
|
+
| `IMAGE` | Responsive image |
|
|
192
|
+
| `INPUT` | Text / textarea input field |
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Components (COPY)
|
|
197
|
+
|
|
198
|
+
Reuse elements across pages with `COPY FROM`:
|
|
199
|
+
|
|
200
|
+
```cobol
|
|
201
|
+
* components/nav.rcl — a full .rcl file with its own DATA and PROCEDURE
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
```cobol
|
|
205
|
+
PROCEDURE DIVISION.
|
|
206
|
+
|
|
207
|
+
RENDER-NAV.
|
|
208
|
+
COPY FROM "components/nav.rcl".
|
|
209
|
+
|
|
210
|
+
RENDER-FOOTER.
|
|
211
|
+
COPY FROM "components/footer.rcl".
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
The compiler merges the component's data into the parent's DATA division
|
|
215
|
+
and inlines its procedure statements at the COPY position. The output is
|
|
216
|
+
still one self-contained HTML file.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Library Usage
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
import { parse } from '@semanticintent/recall/parser'
|
|
224
|
+
import { generate } from '@semanticintent/recall/generator'
|
|
225
|
+
import { compile } from '@semanticintent/recall/compiler'
|
|
226
|
+
|
|
227
|
+
// Compile file → HTML file
|
|
228
|
+
const result = compile('my-site.rcl', 'dist/')
|
|
229
|
+
if (!result.ok) console.error(result.error)
|
|
230
|
+
|
|
231
|
+
// Parse source → AST
|
|
232
|
+
const program = parse(source)
|
|
233
|
+
|
|
234
|
+
// Generate HTML from AST
|
|
235
|
+
const html = generate(program, source)
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Examples
|
|
241
|
+
|
|
242
|
+
See [`examples/`](examples/) for working `.rcl` files:
|
|
243
|
+
|
|
244
|
+
- [`examples/portfolio.rcl`](examples/portfolio.rcl) — personal portfolio page
|
|
245
|
+
- [`examples/landing.rcl`](examples/landing.rcl) — RECALL's own landing page (written in RECALL)
|
|
246
|
+
- [`examples/components/nav.rcl`](examples/components/nav.rcl) — reusable nav component
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Roadmap
|
|
251
|
+
|
|
252
|
+
- [x] Four-division language structure
|
|
253
|
+
- [x] Full element library (16 elements)
|
|
254
|
+
- [x] COPY — component-based composability
|
|
255
|
+
- [ ] Multi-page `recall build` with project manifest
|
|
256
|
+
- [ ] Shared theme inheritance (`COPY PALETTE FROM "theme.rcl"`)
|
|
257
|
+
- [ ] Opt-in vanilla JS interactions (tabs, accordion, modal)
|
|
258
|
+
- [ ] Compile-time data binding from JSON / CSV
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Contributing
|
|
263
|
+
|
|
264
|
+
Pull requests welcome. Please open an issue first for significant changes.
|
|
265
|
+
|
|
266
|
+
```sh
|
|
267
|
+
git clone https://github.com/semanticintent/recall
|
|
268
|
+
cd recall
|
|
269
|
+
npm install
|
|
270
|
+
npm test # 37 tests
|
|
271
|
+
npm run build # compile TypeScript
|
|
272
|
+
node bin/recall.js compile examples/landing.rcl
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## License
|
|
278
|
+
|
|
279
|
+
MIT © [semanticintent](https://github.com/semanticintent)
|
package/bin/recall.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGnC,eAAO,MAAM,YAAY,SAgBrB,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { check } from '../../compiler/index.js';
|
|
3
|
+
export const checkCommand = new Command('check')
|
|
4
|
+
.argument('<file>', 'path to .rcl source file')
|
|
5
|
+
.description('Validate .rcl syntax without compiling')
|
|
6
|
+
.action((file) => {
|
|
7
|
+
const result = check(file);
|
|
8
|
+
if (result.ok) {
|
|
9
|
+
console.log(`\n✓ SYNTAX VALID`);
|
|
10
|
+
console.log(` FILE: ${result.inputPath}\n`);
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
console.error(`\nRECALL SYNTAX ERRORS`);
|
|
14
|
+
console.error(` FILE: ${result.inputPath}\n`);
|
|
15
|
+
result.errors.forEach(e => console.error(` ✗ ${e}`));
|
|
16
|
+
console.error('');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../../src/cli/commands/check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AAE/C,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;KAC7C,QAAQ,CAAC,QAAQ,EAAE,0BAA0B,CAAC;KAC9C,WAAW,CAAC,wCAAwC,CAAC;KACrD,MAAM,CAAC,CAAC,IAAY,EAAE,EAAE;IACvB,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAA;IAE1B,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAA;QAC/B,OAAO,CAAC,GAAG,CAAC,WAAW,MAAM,CAAC,SAAS,IAAI,CAAC,CAAA;IAC9C,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;QACvC,OAAO,CAAC,KAAK,CAAC,WAAW,MAAM,CAAC,SAAS,IAAI,CAAC,CAAA;QAC9C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAA;QACrD,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACjB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/compile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGnC,eAAO,MAAM,cAAc,SAiBvB,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { compile } from '../../compiler/index.js';
|
|
3
|
+
export const compileCommand = new Command('compile')
|
|
4
|
+
.argument('<file>', 'path to .rcl source file')
|
|
5
|
+
.option('--out <dir>', 'output directory (default: same as source)')
|
|
6
|
+
.description('Transpile a .rcl source file to a self-contained HTML file')
|
|
7
|
+
.action((file, options) => {
|
|
8
|
+
const result = compile(file, options.out);
|
|
9
|
+
if (result.ok) {
|
|
10
|
+
console.log(`\n✓ COMPILED SUCCESSFULLY`);
|
|
11
|
+
console.log(` SOURCE: ${result.inputPath}`);
|
|
12
|
+
console.log(` OUTPUT: ${result.outputPath}\n`);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
console.error(`\nRECALL COMPILATION ERROR`);
|
|
16
|
+
console.error(` FILE: ${result.inputPath}`);
|
|
17
|
+
console.error(`\n ${result.error}\n`);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=compile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile.js","sourceRoot":"","sources":["../../../src/cli/commands/compile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AAEjD,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC;KACjD,QAAQ,CAAC,QAAQ,EAAE,0BAA0B,CAAC;KAC9C,MAAM,CAAC,aAAa,EAAE,4CAA4C,CAAC;KACnE,WAAW,CAAC,4DAA4D,CAAC;KACzE,MAAM,CAAC,CAAC,IAAY,EAAE,OAAyB,EAAE,EAAE;IAClD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAA;IAEzC,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAA;QACxC,OAAO,CAAC,GAAG,CAAC,aAAa,MAAM,CAAC,SAAS,EAAE,CAAC,CAAA;QAC5C,OAAO,CAAC,GAAG,CAAC,aAAa,MAAM,CAAC,UAAU,IAAI,CAAC,CAAA;IACjD,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAA;QAC3C,OAAO,CAAC,KAAK,CAAC,WAAW,MAAM,CAAC,SAAS,EAAE,CAAC,CAAA;QAC5C,OAAO,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,KAAK,IAAI,CAAC,CAAA;QACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { compileCommand } from './commands/compile.js';
|
|
3
|
+
import { checkCommand } from './commands/check.js';
|
|
4
|
+
const program = new Command();
|
|
5
|
+
program
|
|
6
|
+
.name('recall')
|
|
7
|
+
.description('RECALL — the source that remembers. A COBOL-inspired web interface language.')
|
|
8
|
+
.version('0.1.0');
|
|
9
|
+
program.addCommand(compileCommand);
|
|
10
|
+
program.addCommand(checkCommand);
|
|
11
|
+
program.parse();
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAElD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;AAE7B,OAAO;KACJ,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CAAC,8EAA8E,CAAC;KAC3F,OAAO,CAAC,OAAO,CAAC,CAAA;AAEnB,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAA;AAClC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAA;AAEhC,OAAO,CAAC,KAAK,EAAE,CAAA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface CompileResult {
|
|
2
|
+
ok: boolean;
|
|
3
|
+
inputPath: string;
|
|
4
|
+
outputPath?: string;
|
|
5
|
+
error?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface CheckResult {
|
|
8
|
+
ok: boolean;
|
|
9
|
+
inputPath: string;
|
|
10
|
+
errors: string[];
|
|
11
|
+
}
|
|
12
|
+
export declare function compile(inputPath: string, outDir?: string): CompileResult;
|
|
13
|
+
export declare function check(inputPath: string): CheckResult;
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/compiler/index.ts"],"names":[],"mappings":"AAiDA,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAA;IACX,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,OAAO,CAAA;IACX,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB;AAED,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,aAAa,CA4CzE;AAED,wBAAgB,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,CAoCpD"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────
|
|
2
|
+
// RECALL Compiler — orchestrates parse → generate
|
|
3
|
+
// ─────────────────────────────────────────────────────────
|
|
4
|
+
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
5
|
+
import { resolve, basename, dirname, join } from 'node:path';
|
|
6
|
+
import { parse } from '../parser/rcl.js';
|
|
7
|
+
import { generate } from '../generator/html.js';
|
|
8
|
+
// ─────────────────────────────────────────────────────────
|
|
9
|
+
// COPY resolution — merges component files into the AST
|
|
10
|
+
// ─────────────────────────────────────────────────────────
|
|
11
|
+
function resolveStatementsInPlace(statements, data, dir) {
|
|
12
|
+
let i = 0;
|
|
13
|
+
while (i < statements.length) {
|
|
14
|
+
const stmt = statements[i];
|
|
15
|
+
if (stmt.element === 'COPY') {
|
|
16
|
+
const filePath = resolve(dir, stmt.value);
|
|
17
|
+
const componentSource = readFileSync(filePath, 'utf-8');
|
|
18
|
+
const component = parse(componentSource);
|
|
19
|
+
// Merge component data into parent
|
|
20
|
+
data.workingStorage.push(...component.data.workingStorage);
|
|
21
|
+
data.items.push(...component.data.items);
|
|
22
|
+
// Inline all component procedure statements (flatten sections)
|
|
23
|
+
const inlined = component.procedure.sections.flatMap(s => s.statements);
|
|
24
|
+
statements.splice(i, 1, ...inlined);
|
|
25
|
+
i += inlined.length;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
// Recurse into SECTION children so COPY works inside DISPLAY SECTION too
|
|
29
|
+
if (stmt.children.length > 0) {
|
|
30
|
+
resolveStatementsInPlace(stmt.children, data, dir);
|
|
31
|
+
}
|
|
32
|
+
i++;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function resolveIncludes(program, dir) {
|
|
37
|
+
for (const section of program.procedure.sections) {
|
|
38
|
+
resolveStatementsInPlace(section.statements, program.data, dir);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export function compile(inputPath, outDir) {
|
|
42
|
+
const absInput = resolve(inputPath);
|
|
43
|
+
if (!existsSync(absInput)) {
|
|
44
|
+
return { ok: false, inputPath: absInput, error: `FILE NOT FOUND: ${absInput}` };
|
|
45
|
+
}
|
|
46
|
+
if (!absInput.endsWith('.rcl')) {
|
|
47
|
+
return { ok: false, inputPath: absInput, error: `NOT A RECALL SOURCE FILE. EXPECTED .rcl EXTENSION.` };
|
|
48
|
+
}
|
|
49
|
+
let source;
|
|
50
|
+
try {
|
|
51
|
+
source = readFileSync(absInput, 'utf-8');
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
return { ok: false, inputPath: absInput, error: `CANNOT READ FILE: ${err.message}` };
|
|
55
|
+
}
|
|
56
|
+
let program;
|
|
57
|
+
try {
|
|
58
|
+
program = parse(source);
|
|
59
|
+
resolveIncludes(program, dirname(absInput));
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
return { ok: false, inputPath: absInput, error: `PARSE ERROR: ${err.message}` };
|
|
63
|
+
}
|
|
64
|
+
let html;
|
|
65
|
+
try {
|
|
66
|
+
html = generate(program, source);
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
return { ok: false, inputPath: absInput, error: `GENERATION ERROR: ${err.message}` };
|
|
70
|
+
}
|
|
71
|
+
const outputDir = outDir ? resolve(outDir) : dirname(absInput);
|
|
72
|
+
const outputName = basename(absInput, '.rcl') + '.html';
|
|
73
|
+
const outputPath = join(outputDir, outputName);
|
|
74
|
+
try {
|
|
75
|
+
writeFileSync(outputPath, html, 'utf-8');
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
return { ok: false, inputPath: absInput, error: `CANNOT WRITE OUTPUT: ${err.message}` };
|
|
79
|
+
}
|
|
80
|
+
return { ok: true, inputPath: absInput, outputPath };
|
|
81
|
+
}
|
|
82
|
+
export function check(inputPath) {
|
|
83
|
+
const absInput = resolve(inputPath);
|
|
84
|
+
const errors = [];
|
|
85
|
+
if (!existsSync(absInput)) {
|
|
86
|
+
return { ok: false, inputPath: absInput, errors: [`FILE NOT FOUND: ${absInput}`] };
|
|
87
|
+
}
|
|
88
|
+
if (!absInput.endsWith('.rcl')) {
|
|
89
|
+
return { ok: false, inputPath: absInput, errors: ['NOT A RECALL SOURCE FILE. EXPECTED .rcl EXTENSION.'] };
|
|
90
|
+
}
|
|
91
|
+
let source;
|
|
92
|
+
try {
|
|
93
|
+
source = readFileSync(absInput, 'utf-8');
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
return { ok: false, inputPath: absInput, errors: [`CANNOT READ FILE: ${err.message}`] };
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
const program = parse(source);
|
|
100
|
+
if (!program.identification.programId) {
|
|
101
|
+
errors.push('IDENTIFICATION DIVISION: PROGRAM-ID IS REQUIRED.');
|
|
102
|
+
}
|
|
103
|
+
if (!program.identification.pageTitle) {
|
|
104
|
+
errors.push('IDENTIFICATION DIVISION: PAGE-TITLE IS REQUIRED.');
|
|
105
|
+
}
|
|
106
|
+
if (program.procedure.sections.length === 0) {
|
|
107
|
+
errors.push('PROCEDURE DIVISION: NO SECTIONS FOUND. AT LEAST ONE RENDER SECTION IS REQUIRED.');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
errors.push(`PARSE ERROR: ${err.message}`);
|
|
112
|
+
}
|
|
113
|
+
return { ok: errors.length === 0, inputPath: absInput, errors };
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/compiler/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ReclProgram, DataDivision, DisplayStatement } from '../parser/rcl.js';
|
|
2
|
+
export declare function renderStatement(stmt: DisplayStatement, data: DataDivision): string;
|
|
3
|
+
export declare function generate(program: ReclProgram, source: string): string;
|
|
4
|
+
//# sourceMappingURL=html.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/generator/html.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,WAAW,EAEX,YAAY,EAEZ,gBAAgB,EAEjB,MAAM,kBAAkB,CAAA;AAyTzB,wBAAgB,eAAe,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,CA0BlF;AAMD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CA8CrE"}
|