english-lang 0.2.5 → 0.2.6

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 (3) hide show
  1. package/README.md +25 -18
  2. package/dist/cli/engc.js +80 -33
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -91,31 +91,38 @@ export function HomeScreen({ navigation }: any) {
91
91
  ## Project structure
92
92
 
93
93
  ```
94
- my-app/
95
- ├── package.json devDependency: english-lang
96
- ├── screens/ ← write your .eng files here
97
- │ ├── HomeScreen.eng
98
- │ └── ProductScreen.eng
99
- └── rn/ react native project (npx react-native init rn)
100
- ├── src/ engc compiles .tsx here automatically
101
- ├── HomeScreen.tsx
102
- └── ProductScreen.tsx
103
- ├── ios/
104
- ├── android/
105
- └── package.json
94
+ MyApp/ ← project root (.eng world)
95
+ ├── package.json compile / watch scripts only
96
+ ├── screens/ ← write your .eng files here
97
+ │ ├── HomeScreen.eng
98
+ │ └── DetailScreen.eng
99
+ └── rn/ entire React Native project
100
+ ├── App.tsx auto-generated by engc (navigation wiring)
101
+ ├── src/ ← auto-generated .tsx (engc output)
102
+ ├── HomeScreen.tsx
103
+ │ └── DetailScreen.tsx
104
+ ├── ios/
105
+ ├── android/
106
+ ├── node_modules/
107
+ ├── index.js
108
+ └── package.json
106
109
  ```
107
110
 
111
+ **Rules:**
112
+ - You only ever edit files in `screens/` — never touch `rn/src/` or `rn/App.tsx`
113
+ - `rn/App.tsx` is regenerated automatically whenever you add, rename, or remove a `.eng` file
114
+ - `rn/src/*.tsx` are regenerated automatically on every save
115
+
108
116
  **Quick start:**
109
117
 
110
118
  ```bash
111
- # One command sets everything up
112
- engc init my-app
113
- cd my-app
119
+ # One command sets everything up: scaffolds RN, installs deps, starts Metro
120
+ engc init MyApp
114
121
 
115
- # Watch .eng files and compile to rn/src/ on every save
116
- npm run watch
122
+ # From inside MyApp/ Metro + eng watcher in one command
123
+ npm run dev
117
124
 
118
- # In a separate terminal, run the app
125
+ # In a separate terminal run on device / simulator
119
126
  cd rn && npx react-native run-ios
120
127
  ```
121
128
 
package/dist/cli/engc.js CHANGED
@@ -50,32 +50,69 @@ const fs = __importStar(require("fs"));
50
50
  const path = __importStar(require("path"));
51
51
  const childProcess = __importStar(require("child_process"));
52
52
  const index_1 = require("../index");
53
- // ── Starter App.tsx ───────────────────────────────────────────
54
- const STARTER_APP_TSX = `\
55
- // App.tsx wired up by engc init
56
- // All screens are generated from .eng source files in screens/
57
-
58
- import React from 'react';
59
- import { NavigationContainer } from '@react-navigation/native';
60
- import { createNativeStackNavigator } from '@react-navigation/native-stack';
61
- import { SafeAreaProvider } from 'react-native-safe-area-context';
62
-
63
- import { HomeScreen } from './src/HomeScreen';
64
-
65
- const Stack = createNativeStackNavigator();
66
-
67
- export default function App() {
68
- return (
69
- <SafeAreaProvider>
70
- <NavigationContainer>
71
- <Stack.Navigator initialRouteName="Home">
72
- <Stack.Screen name="Home" component={HomeScreen} />
73
- </Stack.Navigator>
74
- </NavigationContainer>
75
- </SafeAreaProvider>
76
- );
53
+ // ── App.tsx generator ────────────────────────────────────────
54
+ //
55
+ // Reads every .eng file in screens/, extracts the screen name from
56
+ // the first `screen Foo:` declaration, then writes rn/App.tsx with
57
+ // all screens wired into the navigator automatically.
58
+ // Called on init and after every file change during `engc dev`.
59
+ function screenNamesFromDir(screensDir) {
60
+ if (!fs.existsSync(screensDir))
61
+ return [];
62
+ const names = [];
63
+ for (const file of fs.readdirSync(screensDir)) {
64
+ if (!file.endsWith('.eng'))
65
+ continue;
66
+ try {
67
+ const src = fs.readFileSync(path.join(screensDir, file), 'utf8');
68
+ const m = src.match(/^\s*screen\s+(\w+)/m);
69
+ if (m)
70
+ names.push(m[1]);
71
+ }
72
+ catch { /* skip unreadable files */ }
73
+ }
74
+ return names;
75
+ }
76
+ function generateAppTsx(screensDir, rnDir) {
77
+ const names = screenNamesFromDir(screensDir);
78
+ if (names.length === 0)
79
+ return;
80
+ const initial = names.includes('HomeScreen') ? 'HomeScreen' : names[0];
81
+ const imports = names
82
+ .map(n => `import { ${n} } from './src/${n}';`)
83
+ .join('\n');
84
+ const stackScreens = names
85
+ .map(n => ` <Stack.Screen name="${n}" component={${n}} />`)
86
+ .join('\n');
87
+ const content = [
88
+ `// App.tsx — auto-generated by engc`,
89
+ `// Do not edit — add new screens by creating .eng files in screens/`,
90
+ ``,
91
+ `import React from 'react';`,
92
+ `import { NavigationContainer } from '@react-navigation/native';`,
93
+ `import { createNativeStackNavigator } from '@react-navigation/native-stack';`,
94
+ `import { SafeAreaProvider } from 'react-native-safe-area-context';`,
95
+ ``,
96
+ imports,
97
+ ``,
98
+ `const Stack = createNativeStackNavigator();`,
99
+ ``,
100
+ `export default function App() {`,
101
+ ` return (`,
102
+ ` <SafeAreaProvider>`,
103
+ ` <NavigationContainer>`,
104
+ ` <Stack.Navigator initialRouteName="${initial}">`,
105
+ stackScreens,
106
+ ` </Stack.Navigator>`,
107
+ ` </NavigationContainer>`,
108
+ ` </SafeAreaProvider>`,
109
+ ` );`,
110
+ `}`,
111
+ ``,
112
+ ].join('\n');
113
+ fs.writeFileSync(path.join(rnDir, 'App.tsx'), content, 'utf8');
114
+ console.log(`[engc] rn/App.tsx → ${names.length} screen${names.length === 1 ? '' : 's'} registered`);
77
115
  }
78
- `;
79
116
  // ── Starter .eng file ─────────────────────────────────────────
80
117
  const STARTER_ENG = `\
81
118
  screen HomeScreen:
@@ -122,8 +159,9 @@ function devProject(projectDir = process.cwd()) {
122
159
  metro.on('error', (err) => {
123
160
  console.error('[engc] Metro error:', err.message);
124
161
  });
125
- // Watch .eng files
162
+ // Initial compile + App.tsx generation
126
163
  compileDir(screensDir, rnSrcDir);
164
+ generateAppTsx(screensDir, rnDir);
127
165
  console.log(`[engc] Watching screens/ ...\n`);
128
166
  fs.watch(screensDir, { recursive: false }, (event, filename) => {
129
167
  if (!filename || !filename.endsWith('.eng'))
@@ -132,6 +170,7 @@ function devProject(projectDir = process.cwd()) {
132
170
  if (!fs.existsSync(filePath))
133
171
  return;
134
172
  compileFile(filePath, rnSrcDir);
173
+ generateAppTsx(screensDir, rnDir); // re-register screens on every change
135
174
  });
136
175
  // Keep alive — exit both on Ctrl+C
137
176
  process.on('SIGINT', () => {
@@ -183,9 +222,8 @@ function initProject(name) {
183
222
  const rnDir = path.join(projectDir, 'rn');
184
223
  console.log('\n[engc] Installing React Navigation ...');
185
224
  childProcess.execSync('npm install @react-navigation/native @react-navigation/native-stack react-native-screens react-native-safe-area-context', { cwd: rnDir, stdio: 'inherit' });
186
- // Patch App.tsx to import the compiled HomeScreen
187
- fs.writeFileSync(path.join(rnDir, 'App.tsx'), STARTER_APP_TSX, 'utf8');
188
- console.log('[engc] Patched rn/App.tsx');
225
+ // Compile starter screens, then generate App.tsx from them
226
+ fs.mkdirSync(rnSrcDir, { recursive: true });
189
227
  // Pod install for iOS
190
228
  const iosDir = path.join(rnDir, 'ios');
191
229
  if (fs.existsSync(iosDir)) {
@@ -200,10 +238,9 @@ function initProject(name) {
200
238
  console.warn('[engc] Pod install failed — run it manually: cd rn/ios && pod install');
201
239
  }
202
240
  }
203
- // Compile starter screens into rn/src/
204
- fs.mkdirSync(rnSrcDir, { recursive: true });
205
241
  console.log('\n[engc] Compiling starter screens ...');
206
242
  compileDir(screensDir, rnSrcDir);
243
+ generateAppTsx(screensDir, rnDir);
207
244
  console.log('\n[engc] All done! Starting Metro + eng watcher ...\n');
208
245
  // Auto-start dev mode immediately
209
246
  devProject(projectDir);
@@ -239,8 +276,10 @@ function compileDir(srcDir, outDir) {
239
276
  compileFile(path.join(srcDir, file), outDir);
240
277
  }
241
278
  }
242
- function watchDir(srcDir, outDir) {
279
+ function watchDir(srcDir, outDir, rnDir = null) {
243
280
  compileDir(srcDir, outDir);
281
+ if (rnDir)
282
+ generateAppTsx(srcDir, rnDir);
244
283
  console.log(`[engc] Watching ${srcDir} ...`);
245
284
  fs.watch(srcDir, { recursive: false }, (event, filename) => {
246
285
  if (!filename || !filename.endsWith('.eng'))
@@ -249,6 +288,8 @@ function watchDir(srcDir, outDir) {
249
288
  if (!fs.existsSync(filePath))
250
289
  return;
251
290
  compileFile(filePath, outDir);
291
+ if (rnDir)
292
+ generateAppTsx(srcDir, rnDir);
252
293
  });
253
294
  }
254
295
  // ── CLI entry point ───────────────────────────────────────────
@@ -304,11 +345,17 @@ Examples:
304
345
  console.error(`[engc] Directory not found: ${srcDir}`);
305
346
  process.exit(1);
306
347
  }
348
+ // If outDir is rn/src/, its parent (rn/) is the RN project — regenerate App.tsx
349
+ const maybeRnDir = outDir ? path.dirname(outDir) : null;
350
+ const shouldGenApp = maybeRnDir != null
351
+ && fs.existsSync(path.join(maybeRnDir, 'package.json'));
307
352
  if (cmd === 'compile') {
308
353
  compileDir(srcDir, outDir);
354
+ if (shouldGenApp)
355
+ generateAppTsx(srcDir, maybeRnDir);
309
356
  }
310
357
  else {
311
- watchDir(srcDir, outDir);
358
+ watchDir(srcDir, outDir, shouldGenApp ? maybeRnDir : null);
312
359
  }
313
360
  return;
314
361
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "english-lang",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "The English (.eng) programming language compiler",
5
5
  "main": "./dist/index.js",
6
6
  "bin": {