english-lang 0.2.4 → 0.2.5

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.
@@ -69,8 +69,15 @@ class ReactNativeBackend {
69
69
  this.emitTypeDecl(type);
70
70
  }
71
71
  // Component function
72
- this.line(`export function ${screen.name}({ navigation }: any) {`);
72
+ const hasRouteParams = screen.receives && screen.receives.length > 0;
73
+ const propsArg = hasRouteParams ? '{ navigation, route }' : '{ navigation }';
74
+ this.line(`export function ${screen.name}(${propsArg}: any) {`);
73
75
  this.depth++;
76
+ // Destructure navigation params
77
+ if (hasRouteParams) {
78
+ this.line(`const { ${screen.receives.join(', ')} } = (route.params ?? {}) as any;`);
79
+ this.line('');
80
+ }
74
81
  // useState hooks
75
82
  for (const field of screen.state) {
76
83
  const tsType = this.tsType(field, stateVarTypes);
@@ -83,10 +90,22 @@ class ReactNativeBackend {
83
90
  // useEffect for screen opens
84
91
  const screenOpensHandler = screen.events.find(e => e.trigger.kind === 'ScreenOpens');
85
92
  if (screenOpensHandler) {
93
+ const isAsync = this.bodyIsAsync(screenOpensHandler.body);
86
94
  this.line('useEffect(() => {');
87
95
  this.depth++;
88
- for (const stmt of screenOpensHandler.body) {
89
- this.emitStatement(stmt, stateVarTypes);
96
+ if (isAsync) {
97
+ this.line('(async () => {');
98
+ this.depth++;
99
+ for (const stmt of screenOpensHandler.body) {
100
+ this.emitStatement(stmt, stateVarTypes);
101
+ }
102
+ this.depth--;
103
+ this.line('})();');
104
+ }
105
+ else {
106
+ for (const stmt of screenOpensHandler.body) {
107
+ this.emitStatement(stmt, stateVarTypes);
108
+ }
90
109
  }
91
110
  this.depth--;
92
111
  this.line('}, []);');
@@ -97,7 +116,8 @@ class ReactNativeBackend {
97
116
  if (event.trigger.kind !== 'ButtonPressed')
98
117
  continue;
99
118
  const fnName = buttonHandlers.get(event.trigger.label);
100
- this.line(`const ${fnName} = () => {`);
119
+ const asyncKw = this.bodyIsAsync(event.body) ? 'async ' : '';
120
+ this.line(`const ${fnName} = ${asyncKw}() => {`);
101
121
  this.depth++;
102
122
  for (const stmt of event.body) {
103
123
  this.emitStatement(stmt, stateVarTypes);
@@ -221,6 +241,10 @@ class ReactNativeBackend {
221
241
  }
222
242
  this.depth--;
223
243
  }
244
+ else {
245
+ this.line(`} catch (_e) {`);
246
+ this.line(` // network error — add "on failure: (err) ->" to handle it`);
247
+ }
224
248
  this.line(`}`);
225
249
  break;
226
250
  }
@@ -647,6 +671,18 @@ class ReactNativeBackend {
647
671
  };
648
672
  return map[name] ?? name;
649
673
  }
674
+ bodyIsAsync(stmts) {
675
+ return stmts.some(s => {
676
+ if (s.kind === 'FetchStatement')
677
+ return true;
678
+ if (s.kind === 'IfStatement') {
679
+ return this.bodyIsAsync(s.thenBody)
680
+ || s.otherwiseIfBranches.some(b => this.bodyIsAsync(b.body))
681
+ || (s.elseBody ? this.bodyIsAsync(s.elseBody) : false);
682
+ }
683
+ return false;
684
+ });
685
+ }
650
686
  hasSlider(layout) {
651
687
  const scan = (nodes) => {
652
688
  for (const node of nodes) {
@@ -55,6 +55,7 @@ class Parser {
55
55
  this.expect('NEWLINE');
56
56
  this.expect('INDENT');
57
57
  let title = null;
58
+ const receives = [];
58
59
  const state = [];
59
60
  const events = [];
60
61
  const actions = [];
@@ -70,6 +71,21 @@ class Parser {
70
71
  title = this.expect('STRING').value;
71
72
  this.expectNewline();
72
73
  }
74
+ else if (word === 'receives') {
75
+ // receives: param1, param2 ... (navigation route.params)
76
+ this.consumeWord();
77
+ this.expect('COLON');
78
+ this.expect('NEWLINE');
79
+ this.expect('INDENT');
80
+ while (!this.check('DEDENT') && !this.check('EOF')) {
81
+ this.skipNewlines();
82
+ if (this.check('DEDENT'))
83
+ break;
84
+ receives.push(this.expectWord());
85
+ this.expectNewline();
86
+ }
87
+ this.expect('DEDENT');
88
+ }
73
89
  else if (word === 'state') {
74
90
  this.consumeWord();
75
91
  this.expect('COLON');
@@ -110,7 +126,7 @@ class Parser {
110
126
  }
111
127
  }
112
128
  this.expect('DEDENT');
113
- return { kind: 'ScreenDecl', name, title, state, events, actions, layout, line };
129
+ return { kind: 'ScreenDecl', name, title, receives, state, events, actions, layout, line };
114
130
  }
115
131
  // ── State field ───────────────────────────────────────────
116
132
  //
@@ -1321,8 +1337,17 @@ class Parser {
1321
1337
  if (word === 'when') {
1322
1338
  events.push(this.parseEventHandler());
1323
1339
  }
1340
+ else if (word === 'layout') {
1341
+ // Optional layout: section header (same as screens)
1342
+ this.consumeWord();
1343
+ this.expect('COLON');
1344
+ this.expect('NEWLINE');
1345
+ this.expect('INDENT');
1346
+ layout = this.parseLayoutNodes();
1347
+ this.expect('DEDENT');
1348
+ }
1324
1349
  else {
1325
- // Everything else is layout
1350
+ // Layout nodes written directly (without layout: header)
1326
1351
  layout = this.parseLayoutNodes();
1327
1352
  }
1328
1353
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "english-lang",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "description": "The English (.eng) programming language compiler",
5
5
  "main": "./dist/index.js",
6
6
  "bin": {