imxc 0.2.0 → 0.3.1
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/compile.d.ts +10 -0
- package/dist/compile.js +169 -0
- package/dist/components.js +249 -1
- package/dist/diagnostics.d.ts +5 -0
- package/dist/diagnostics.js +23 -0
- package/dist/emitter.d.ts +3 -3
- package/dist/emitter.js +814 -84
- package/dist/index.js +39 -111
- package/dist/init.d.ts +1 -0
- package/dist/init.js +202 -17
- package/dist/ir.d.ts +157 -3
- package/dist/lowering.d.ts +1 -0
- package/dist/lowering.js +400 -63
- package/dist/validator.js +3 -5
- package/dist/watch.d.ts +4 -0
- package/dist/watch.js +66 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { parseArgs } from 'node:util';
|
|
3
|
-
import * as fs from 'node:fs';
|
|
4
3
|
import * as path from 'node:path';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { emitComponent, emitComponentHeader, emitRoot } from './emitter.js';
|
|
9
|
-
import { initProject } from './init.js';
|
|
4
|
+
import { initProject, addToProject } from './init.js';
|
|
5
|
+
import { compile } from './compile.js';
|
|
6
|
+
import { startWatch } from './watch.js';
|
|
10
7
|
// Handle `imxc init [dir]` subcommand
|
|
11
8
|
if (process.argv[2] === 'init') {
|
|
12
9
|
const dir = process.argv[3] ?? '.';
|
|
@@ -14,115 +11,46 @@ if (process.argv[2] === 'init') {
|
|
|
14
11
|
initProject(absDir, path.basename(absDir));
|
|
15
12
|
process.exit(0);
|
|
16
13
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
console.error(' imxc init [project-dir]');
|
|
24
|
-
process.exit(1);
|
|
14
|
+
// Handle `imxc add [dir]` subcommand
|
|
15
|
+
if (process.argv[2] === 'add') {
|
|
16
|
+
const dir = process.argv[3] ?? '.';
|
|
17
|
+
const absDir = path.resolve(dir);
|
|
18
|
+
addToProject(absDir);
|
|
19
|
+
process.exit(0);
|
|
25
20
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (!fs.existsSync(file)) {
|
|
33
|
-
console.error(`${file}:1:1 - error: file not found`);
|
|
34
|
-
hasErrors = true;
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
const source = fs.readFileSync(file, 'utf-8');
|
|
38
|
-
const parsed = parseFile(file, source);
|
|
39
|
-
if (parsed.errors.length > 0) {
|
|
40
|
-
parsed.errors.forEach(e => console.error(`${e.file}:${e.line}:${e.col} - error: ${e.message}`));
|
|
41
|
-
hasErrors = true;
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
const validation = validate(parsed);
|
|
45
|
-
if (validation.errors.length > 0) {
|
|
46
|
-
validation.errors.forEach(e => console.error(`${e.file}:${e.line}:${e.col} - error: ${e.message}`));
|
|
47
|
-
hasErrors = true;
|
|
48
|
-
continue;
|
|
21
|
+
// Handle `imxc watch <dir> -o <output-dir>` subcommand
|
|
22
|
+
if (process.argv[2] === 'watch') {
|
|
23
|
+
const watchDir = process.argv[3];
|
|
24
|
+
if (!watchDir) {
|
|
25
|
+
console.error('Usage: imxc watch <dir> -o <output-dir>');
|
|
26
|
+
process.exit(1);
|
|
49
27
|
}
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
stateCount: ir.stateSlots.length,
|
|
55
|
-
bufferCount: ir.bufferCount,
|
|
56
|
-
ir,
|
|
57
|
-
imports,
|
|
58
|
-
hasProps: ir.params.length > 0,
|
|
28
|
+
const { values } = parseArgs({
|
|
29
|
+
args: process.argv.slice(4),
|
|
30
|
+
allowPositionals: false,
|
|
31
|
+
options: { output: { type: 'string', short: 'o' } },
|
|
59
32
|
});
|
|
33
|
+
const outputDir = values.output ?? '.';
|
|
34
|
+
startWatch(path.resolve(watchDir), path.resolve(outputDir));
|
|
60
35
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const importInfos = [];
|
|
74
|
-
for (const [importedName] of comp.imports) {
|
|
75
|
-
const importedComp = componentMap.get(importedName);
|
|
76
|
-
if (importedComp && importedComp.hasProps) {
|
|
77
|
-
importInfos.push({
|
|
78
|
-
name: importedName,
|
|
79
|
-
headerFile: `${importedName}.gen.h`,
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
// Emit .gen.cpp
|
|
84
|
-
const cppOutput = emitComponent(comp.ir, importInfos);
|
|
85
|
-
const baseName = comp.name;
|
|
86
|
-
const outPath = path.join(outputDir, `${baseName}.gen.cpp`);
|
|
87
|
-
fs.writeFileSync(outPath, cppOutput);
|
|
88
|
-
console.log(` ${baseName} -> ${outPath}`);
|
|
89
|
-
// Emit .gen.h for components with props
|
|
90
|
-
if (comp.hasProps) {
|
|
91
|
-
const headerOutput = emitComponentHeader(comp.ir);
|
|
92
|
-
const headerPath = path.join(outputDir, `${baseName}.gen.h`);
|
|
93
|
-
fs.writeFileSync(headerPath, headerOutput);
|
|
94
|
-
console.log(` ${baseName} -> ${headerPath} (header)`);
|
|
36
|
+
else {
|
|
37
|
+
// Default: build command
|
|
38
|
+
const { values, positionals } = parseArgs({
|
|
39
|
+
allowPositionals: true,
|
|
40
|
+
options: { output: { type: 'string', short: 'o' } },
|
|
41
|
+
});
|
|
42
|
+
if (positionals.length === 0) {
|
|
43
|
+
console.error('Usage: imxc <input.tsx ...> -o <output-dir>');
|
|
44
|
+
console.error(' imxc init [project-dir]');
|
|
45
|
+
console.error(' imxc add [project-dir]');
|
|
46
|
+
console.error(' imxc watch <dir> -o <output-dir>');
|
|
47
|
+
process.exit(1);
|
|
95
48
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const rootPath = path.join(outputDir, 'app_root.gen.cpp');
|
|
102
|
-
fs.writeFileSync(rootPath, rootOutput);
|
|
103
|
-
console.log(` -> ${rootPath} (root entry point)`);
|
|
104
|
-
}
|
|
105
|
-
console.log(`imxc: ${compiled.length} component(s) compiled successfully.`);
|
|
106
|
-
/**
|
|
107
|
-
* Walk IR nodes and update custom_component nodes with resolved stateCount/bufferCount
|
|
108
|
-
* from the compiled component map.
|
|
109
|
-
*/
|
|
110
|
-
function resolveCustomComponents(nodes, map) {
|
|
111
|
-
for (const node of nodes) {
|
|
112
|
-
if (node.kind === 'custom_component') {
|
|
113
|
-
const target = map.get(node.name);
|
|
114
|
-
if (target) {
|
|
115
|
-
node.stateCount = target.stateCount;
|
|
116
|
-
node.bufferCount = target.bufferCount;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
else if (node.kind === 'conditional') {
|
|
120
|
-
resolveCustomComponents(node.body, map);
|
|
121
|
-
if (node.elseBody)
|
|
122
|
-
resolveCustomComponents(node.elseBody, map);
|
|
123
|
-
}
|
|
124
|
-
else if (node.kind === 'list_map') {
|
|
125
|
-
resolveCustomComponents(node.body, map);
|
|
126
|
-
}
|
|
49
|
+
const outputDir = values.output ?? '.';
|
|
50
|
+
const result = compile(positionals, outputDir);
|
|
51
|
+
if (!result.success) {
|
|
52
|
+
result.errors.forEach(e => console.error(e));
|
|
53
|
+
process.exit(1);
|
|
127
54
|
}
|
|
55
|
+
console.log(`imxc: ${result.componentCount} component(s) compiled successfully.`);
|
|
128
56
|
}
|
package/dist/init.d.ts
CHANGED
package/dist/init.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as fs from 'node:fs';
|
|
2
2
|
import * as path from 'node:path';
|
|
3
|
-
const MAIN_CPP = `#include <
|
|
4
|
-
#include <
|
|
3
|
+
const MAIN_CPP = `#include <imx/runtime.h>
|
|
4
|
+
#include <imx/renderer.h>
|
|
5
5
|
|
|
6
6
|
#include <imgui.h>
|
|
7
7
|
#include <imgui_impl_glfw.h>
|
|
@@ -11,7 +11,7 @@ const MAIN_CPP = `#include <reimgui/runtime.h>
|
|
|
11
11
|
struct App {
|
|
12
12
|
GLFWwindow* window = nullptr;
|
|
13
13
|
ImGuiIO* io = nullptr;
|
|
14
|
-
|
|
14
|
+
imx::Runtime runtime;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
static void render_frame(App& app) {
|
|
@@ -26,7 +26,7 @@ static void render_frame(App& app) {
|
|
|
26
26
|
ImGui_ImplGlfw_NewFrame();
|
|
27
27
|
ImGui::NewFrame();
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
imx::render_root(app.runtime);
|
|
30
30
|
|
|
31
31
|
ImGui::Render();
|
|
32
32
|
glViewport(0, 0, fb_w, fb_h);
|
|
@@ -122,7 +122,7 @@ const APP_TSX = `export default function App() {
|
|
|
122
122
|
);
|
|
123
123
|
}
|
|
124
124
|
`;
|
|
125
|
-
const
|
|
125
|
+
const IMX_DTS = `// imx.d.ts — Type definitions for IMX components
|
|
126
126
|
|
|
127
127
|
interface Style {
|
|
128
128
|
padding?: number;
|
|
@@ -140,7 +140,7 @@ interface Style {
|
|
|
140
140
|
|
|
141
141
|
declare function useState<T>(initial: T): [T, (value: T) => void];
|
|
142
142
|
|
|
143
|
-
interface WindowProps { title: string; style?: Style; children?: any; }
|
|
143
|
+
interface WindowProps { title: string; open?: boolean; onClose?: () => void; noTitleBar?: boolean; noResize?: boolean; noMove?: boolean; noCollapse?: boolean; noDocking?: boolean; noScrollbar?: boolean; style?: Style; children?: any; }
|
|
144
144
|
interface ViewProps { style?: Style; children?: any; }
|
|
145
145
|
interface RowProps { gap?: number; style?: Style; children?: any; }
|
|
146
146
|
interface ColumnProps { gap?: number; style?: Style; children?: any; }
|
|
@@ -151,6 +151,21 @@ interface CheckboxProps { value: boolean; onChange: (v: boolean) => void; label?
|
|
|
151
151
|
interface SeparatorProps {}
|
|
152
152
|
interface PopupProps { id: string; style?: Style; children?: any; }
|
|
153
153
|
interface DockSpaceProps { style?: Style; children?: any; }
|
|
154
|
+
interface DockLayoutProps { children?: any; }
|
|
155
|
+
interface DockSplitProps { direction: "horizontal" | "vertical"; size: number; children?: any; }
|
|
156
|
+
interface DockPanelProps { children?: any; }
|
|
157
|
+
interface ThemeProps {
|
|
158
|
+
preset: string;
|
|
159
|
+
accentColor?: [number, number, number, number];
|
|
160
|
+
backgroundColor?: [number, number, number, number];
|
|
161
|
+
textColor?: [number, number, number, number];
|
|
162
|
+
borderColor?: [number, number, number, number];
|
|
163
|
+
surfaceColor?: [number, number, number, number];
|
|
164
|
+
rounding?: number;
|
|
165
|
+
borderSize?: number;
|
|
166
|
+
spacing?: number;
|
|
167
|
+
children?: any;
|
|
168
|
+
}
|
|
154
169
|
interface MenuBarProps { children?: any; }
|
|
155
170
|
interface MenuProps { label: string; children?: any; }
|
|
156
171
|
interface MenuItemProps { label: string; onPress?: () => void; shortcut?: string; }
|
|
@@ -171,6 +186,48 @@ interface ColorEditProps { label: string; value: number[]; onChange: (v: number[
|
|
|
171
186
|
interface ListBoxProps { label: string; value: number; onChange: (v: number) => void; items: string[]; style?: Style; }
|
|
172
187
|
interface ProgressBarProps { value: number; overlay?: string; style?: Style; }
|
|
173
188
|
interface TooltipProps { text: string; }
|
|
189
|
+
interface BulletTextProps { style?: Style; children?: any; }
|
|
190
|
+
interface LabelTextProps { label: string; value: string; }
|
|
191
|
+
interface SelectableProps { label: string; selected?: boolean; onSelect?: () => void; style?: Style; }
|
|
192
|
+
interface RadioProps { label: string; value: number; index: number; onChange?: (v: number) => void; style?: Style; }
|
|
193
|
+
interface InputTextMultilineProps { label: string; value: string; style?: Style; }
|
|
194
|
+
interface ColorPickerProps { label: string; value: number[]; style?: Style; }
|
|
195
|
+
interface PlotLinesProps { label: string; values: number[]; overlay?: string; style?: Style; }
|
|
196
|
+
interface PlotHistogramProps { label: string; values: number[]; overlay?: string; style?: Style; }
|
|
197
|
+
interface ModalProps { title: string; open?: boolean; onClose?: () => void; style?: Style; children?: any; }
|
|
198
|
+
interface ImageProps { src: string; embed?: boolean; width?: number; height?: number; }
|
|
199
|
+
interface GroupProps { style?: Style; children?: any; }
|
|
200
|
+
interface IDProps { scope: string | number; children?: any; }
|
|
201
|
+
interface DragDropSourceProps { type: string; payload: number | string; children?: any; }
|
|
202
|
+
interface DragDropTargetProps { type: string; onDrop: (payload: any) => void; children?: any; }
|
|
203
|
+
interface CanvasProps { width: number; height: number; style?: Style; children?: any; }
|
|
204
|
+
interface DrawLineProps { p1: [number, number]; p2: [number, number]; color: [number, number, number, number]; thickness?: number; }
|
|
205
|
+
interface DrawRectProps { min: [number, number]; max: [number, number]; color: [number, number, number, number]; filled?: boolean; thickness?: number; rounding?: number; }
|
|
206
|
+
interface DrawCircleProps { center: [number, number]; radius: number; color: [number, number, number, number]; filled?: boolean; thickness?: number; }
|
|
207
|
+
interface DrawTextProps { pos: [number, number]; text: string; color: [number, number, number, number]; }
|
|
208
|
+
interface StyleColorProps {
|
|
209
|
+
text?: [number, number, number, number];
|
|
210
|
+
textDisabled?: [number, number, number, number];
|
|
211
|
+
windowBg?: [number, number, number, number];
|
|
212
|
+
frameBg?: [number, number, number, number];
|
|
213
|
+
frameBgHovered?: [number, number, number, number];
|
|
214
|
+
frameBgActive?: [number, number, number, number];
|
|
215
|
+
titleBg?: [number, number, number, number];
|
|
216
|
+
titleBgActive?: [number, number, number, number];
|
|
217
|
+
button?: [number, number, number, number];
|
|
218
|
+
buttonHovered?: [number, number, number, number];
|
|
219
|
+
buttonActive?: [number, number, number, number];
|
|
220
|
+
header?: [number, number, number, number];
|
|
221
|
+
headerHovered?: [number, number, number, number];
|
|
222
|
+
headerActive?: [number, number, number, number];
|
|
223
|
+
separator?: [number, number, number, number];
|
|
224
|
+
checkMark?: [number, number, number, number];
|
|
225
|
+
sliderGrab?: [number, number, number, number];
|
|
226
|
+
border?: [number, number, number, number];
|
|
227
|
+
popupBg?: [number, number, number, number];
|
|
228
|
+
tab?: [number, number, number, number];
|
|
229
|
+
children?: any;
|
|
230
|
+
}
|
|
174
231
|
|
|
175
232
|
declare function Window(props: WindowProps): any;
|
|
176
233
|
declare function View(props: ViewProps): any;
|
|
@@ -183,6 +240,10 @@ declare function Checkbox(props: CheckboxProps): any;
|
|
|
183
240
|
declare function Separator(props: SeparatorProps): any;
|
|
184
241
|
declare function Popup(props: PopupProps): any;
|
|
185
242
|
declare function DockSpace(props: DockSpaceProps): any;
|
|
243
|
+
declare function DockLayout(props: DockLayoutProps): any;
|
|
244
|
+
declare function DockSplit(props: DockSplitProps): any;
|
|
245
|
+
declare function DockPanel(props: DockPanelProps): any;
|
|
246
|
+
declare function Theme(props: ThemeProps): any;
|
|
186
247
|
declare function MenuBar(props: MenuBarProps): any;
|
|
187
248
|
declare function Menu(props: MenuProps): any;
|
|
188
249
|
declare function MenuItem(props: MenuItemProps): any;
|
|
@@ -203,8 +264,63 @@ declare function ColorEdit(props: ColorEditProps): any;
|
|
|
203
264
|
declare function ListBox(props: ListBoxProps): any;
|
|
204
265
|
declare function ProgressBar(props: ProgressBarProps): any;
|
|
205
266
|
declare function Tooltip(props: TooltipProps): any;
|
|
267
|
+
declare function BulletText(props: BulletTextProps): any;
|
|
268
|
+
declare function LabelText(props: LabelTextProps): any;
|
|
269
|
+
declare function Selectable(props: SelectableProps): any;
|
|
270
|
+
declare function Radio(props: RadioProps): any;
|
|
271
|
+
declare function InputTextMultiline(props: InputTextMultilineProps): any;
|
|
272
|
+
declare function ColorPicker(props: ColorPickerProps): any;
|
|
273
|
+
declare function PlotLines(props: PlotLinesProps): any;
|
|
274
|
+
declare function PlotHistogram(props: PlotHistogramProps): any;
|
|
275
|
+
declare function Modal(props: ModalProps): any;
|
|
276
|
+
declare function Image(props: ImageProps): any;
|
|
277
|
+
declare function Group(props: GroupProps): any;
|
|
278
|
+
declare function ID(props: IDProps): any;
|
|
279
|
+
declare function StyleColor(props: StyleColorProps): any;
|
|
280
|
+
declare function Canvas(props: CanvasProps): any;
|
|
281
|
+
declare function DrawLine(props: DrawLineProps): any;
|
|
282
|
+
declare function DrawRect(props: DrawRectProps): any;
|
|
283
|
+
declare function DrawCircle(props: DrawCircleProps): any;
|
|
284
|
+
declare function DrawText(props: DrawTextProps): any;
|
|
285
|
+
|
|
286
|
+
interface StyleVarProps {
|
|
287
|
+
alpha?: number;
|
|
288
|
+
windowPadding?: [number, number];
|
|
289
|
+
windowRounding?: number;
|
|
290
|
+
framePadding?: [number, number];
|
|
291
|
+
frameRounding?: number;
|
|
292
|
+
frameBorderSize?: number;
|
|
293
|
+
itemSpacing?: [number, number];
|
|
294
|
+
itemInnerSpacing?: [number, number];
|
|
295
|
+
indentSpacing?: number;
|
|
296
|
+
cellPadding?: [number, number];
|
|
297
|
+
tabRounding?: number;
|
|
298
|
+
children?: any;
|
|
299
|
+
}
|
|
300
|
+
declare function StyleVar(props: StyleVarProps): any;
|
|
301
|
+
declare function DragDropSource(props: DragDropSourceProps): any;
|
|
302
|
+
declare function DragDropTarget(props: DragDropTargetProps): any;
|
|
303
|
+
interface DisabledProps { disabled?: boolean; children?: any; }
|
|
304
|
+
interface ChildProps { id: string; width?: number; height?: number; border?: boolean; style?: Style; children?: any; }
|
|
305
|
+
declare function Disabled(props: DisabledProps): any;
|
|
306
|
+
declare function Child(props: ChildProps): any;
|
|
307
|
+
|
|
308
|
+
declare function resetLayout(): void;
|
|
206
309
|
|
|
207
|
-
|
|
310
|
+
// --- Custom native widgets ---
|
|
311
|
+
// Declare your C++ registered widgets here for type checking:
|
|
312
|
+
//
|
|
313
|
+
// interface KnobProps {
|
|
314
|
+
// value: number;
|
|
315
|
+
// onChange: (value: number) => void;
|
|
316
|
+
// min: number;
|
|
317
|
+
// max: number;
|
|
318
|
+
// width?: number;
|
|
319
|
+
// height?: number;
|
|
320
|
+
// }
|
|
321
|
+
// declare function Knob(props: KnobProps): any;
|
|
322
|
+
|
|
323
|
+
declare module "imx/jsx-runtime" {
|
|
208
324
|
export namespace JSX {
|
|
209
325
|
type Element = any;
|
|
210
326
|
interface IntrinsicElements { [tag: string]: any; }
|
|
@@ -222,12 +338,12 @@ const TSCONFIG = `{
|
|
|
222
338
|
"module": "ES2022",
|
|
223
339
|
"moduleResolution": "bundler",
|
|
224
340
|
"jsx": "react-jsx",
|
|
225
|
-
"jsxImportSource": "
|
|
341
|
+
"jsxImportSource": "imx",
|
|
226
342
|
"strict": false,
|
|
227
343
|
"noEmit": true,
|
|
228
344
|
"skipLibCheck": true
|
|
229
345
|
},
|
|
230
|
-
"include": ["src/**/*.tsx", "src/
|
|
346
|
+
"include": ["src/**/*.tsx", "src/imx.d.ts"]
|
|
231
347
|
}
|
|
232
348
|
`;
|
|
233
349
|
function cmakeTemplate(projectName, repoUrl) {
|
|
@@ -238,17 +354,20 @@ set(CMAKE_CXX_STANDARD 20)
|
|
|
238
354
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
239
355
|
|
|
240
356
|
include(FetchContent)
|
|
357
|
+
set(FETCHCONTENT_QUIET OFF)
|
|
241
358
|
|
|
242
359
|
FetchContent_Declare(
|
|
243
|
-
|
|
360
|
+
imx
|
|
244
361
|
GIT_REPOSITORY ${repoUrl}
|
|
245
362
|
GIT_TAG main
|
|
363
|
+
GIT_PROGRESS TRUE
|
|
246
364
|
)
|
|
247
|
-
|
|
365
|
+
message(STATUS "Fetching IMX (includes ImGui + GLFW)...")
|
|
366
|
+
FetchContent_MakeAvailable(imx)
|
|
248
367
|
|
|
249
|
-
include(
|
|
368
|
+
include(ImxCompile)
|
|
250
369
|
|
|
251
|
-
|
|
370
|
+
imx_compile_tsx(GENERATED
|
|
252
371
|
SOURCES src/App.tsx
|
|
253
372
|
OUTPUT_DIR \${CMAKE_BINARY_DIR}/generated
|
|
254
373
|
)
|
|
@@ -257,10 +376,73 @@ add_executable(${projectName}
|
|
|
257
376
|
src/main.cpp
|
|
258
377
|
\${GENERATED}
|
|
259
378
|
)
|
|
260
|
-
target_link_libraries(${projectName} PRIVATE
|
|
379
|
+
target_link_libraries(${projectName} PRIVATE imx::renderer)
|
|
261
380
|
target_include_directories(${projectName} PRIVATE \${CMAKE_BINARY_DIR}/generated)
|
|
381
|
+
|
|
382
|
+
# Copy public/ assets to output directory
|
|
383
|
+
add_custom_command(TARGET ${projectName} POST_BUILD
|
|
384
|
+
COMMAND \${CMAKE_COMMAND} -E copy_directory
|
|
385
|
+
\${CMAKE_CURRENT_SOURCE_DIR}/public
|
|
386
|
+
$<TARGET_FILE_DIR:${projectName}>
|
|
387
|
+
COMMENT "Copying public/ assets"
|
|
388
|
+
)
|
|
262
389
|
`;
|
|
263
390
|
}
|
|
391
|
+
export function addToProject(projectDir) {
|
|
392
|
+
const srcDir = path.join(projectDir, 'src');
|
|
393
|
+
if (fs.existsSync(path.join(srcDir, 'App.tsx'))) {
|
|
394
|
+
console.error(`Error: ${srcDir}/App.tsx already exists. Aborting.`);
|
|
395
|
+
process.exit(1);
|
|
396
|
+
}
|
|
397
|
+
fs.mkdirSync(srcDir, { recursive: true });
|
|
398
|
+
const publicDir = path.join(projectDir, 'public');
|
|
399
|
+
fs.mkdirSync(publicDir, { recursive: true });
|
|
400
|
+
// Write TSX source files only — no CMakeLists.txt or main.cpp
|
|
401
|
+
fs.writeFileSync(path.join(srcDir, 'App.tsx'), APP_TSX);
|
|
402
|
+
fs.writeFileSync(path.join(srcDir, 'imx.d.ts'), IMX_DTS);
|
|
403
|
+
fs.writeFileSync(path.join(projectDir, 'tsconfig.json'), TSCONFIG);
|
|
404
|
+
console.log(`imxc: added IMX sources to project`);
|
|
405
|
+
console.log('');
|
|
406
|
+
console.log(' Created:');
|
|
407
|
+
console.log(` src/App.tsx — your root component`);
|
|
408
|
+
console.log(` src/imx.d.ts — type definitions for IDE support`);
|
|
409
|
+
console.log(` tsconfig.json — TypeScript config`);
|
|
410
|
+
console.log(` public/ — static assets (copied to exe directory)`);
|
|
411
|
+
console.log('');
|
|
412
|
+
console.log(' Add to your CMakeLists.txt:');
|
|
413
|
+
console.log('');
|
|
414
|
+
console.log(' # --- IMX integration ---');
|
|
415
|
+
console.log(' include(FetchContent)');
|
|
416
|
+
console.log(' FetchContent_Declare(imx');
|
|
417
|
+
console.log(' GIT_REPOSITORY https://github.com/bgocumlu/imx.git');
|
|
418
|
+
console.log(' GIT_TAG main');
|
|
419
|
+
console.log(' )');
|
|
420
|
+
console.log(' FetchContent_MakeAvailable(imx)');
|
|
421
|
+
console.log(' include(ImxCompile)');
|
|
422
|
+
console.log('');
|
|
423
|
+
console.log(' imx_compile_tsx(GENERATED');
|
|
424
|
+
console.log(' SOURCES src/App.tsx');
|
|
425
|
+
console.log(' OUTPUT_DIR ${CMAKE_BINARY_DIR}/generated');
|
|
426
|
+
console.log(' )');
|
|
427
|
+
console.log('');
|
|
428
|
+
console.log(' # Add ${GENERATED} to your target sources:');
|
|
429
|
+
console.log(' target_sources(your_app PRIVATE ${GENERATED})');
|
|
430
|
+
console.log(' target_link_libraries(your_app PRIVATE imx::renderer)');
|
|
431
|
+
console.log(' target_include_directories(your_app PRIVATE ${CMAKE_BINARY_DIR}/generated)');
|
|
432
|
+
console.log('');
|
|
433
|
+
console.log(' # Copy assets to exe directory:');
|
|
434
|
+
console.log(' add_custom_command(TARGET your_app POST_BUILD');
|
|
435
|
+
console.log(' COMMAND ${CMAKE_COMMAND} -E copy_directory');
|
|
436
|
+
console.log(' ${CMAKE_CURRENT_SOURCE_DIR}/public $<TARGET_FILE_DIR:your_app>');
|
|
437
|
+
console.log(' )');
|
|
438
|
+
console.log('');
|
|
439
|
+
console.log(' Then add the IMX render call to your main loop:');
|
|
440
|
+
console.log('');
|
|
441
|
+
console.log(' #include <imx/runtime.h>');
|
|
442
|
+
console.log(' imx::Runtime runtime;');
|
|
443
|
+
console.log(' // In your frame loop, between NewFrame() and Render():');
|
|
444
|
+
console.log(' imx::render_root(runtime);');
|
|
445
|
+
}
|
|
264
446
|
export function initProject(projectDir, projectName) {
|
|
265
447
|
const name = projectName ?? path.basename(projectDir);
|
|
266
448
|
const srcDir = path.join(projectDir, 'src');
|
|
@@ -269,20 +451,23 @@ export function initProject(projectDir, projectName) {
|
|
|
269
451
|
process.exit(1);
|
|
270
452
|
}
|
|
271
453
|
fs.mkdirSync(srcDir, { recursive: true });
|
|
454
|
+
const publicDir = path.join(projectDir, 'public');
|
|
455
|
+
fs.mkdirSync(publicDir, { recursive: true });
|
|
272
456
|
// Write files
|
|
273
457
|
fs.writeFileSync(path.join(srcDir, 'main.cpp'), MAIN_CPP.replace('APP_NAME', name));
|
|
274
458
|
fs.writeFileSync(path.join(srcDir, 'App.tsx'), APP_TSX);
|
|
275
|
-
fs.writeFileSync(path.join(srcDir, '
|
|
459
|
+
fs.writeFileSync(path.join(srcDir, 'imx.d.ts'), IMX_DTS);
|
|
276
460
|
fs.writeFileSync(path.join(projectDir, 'tsconfig.json'), TSCONFIG);
|
|
277
|
-
fs.writeFileSync(path.join(projectDir, 'CMakeLists.txt'), cmakeTemplate(name, 'https://github.com/bgocumlu/
|
|
461
|
+
fs.writeFileSync(path.join(projectDir, 'CMakeLists.txt'), cmakeTemplate(name, 'https://github.com/bgocumlu/imx.git'));
|
|
278
462
|
console.log(`imxc: initialized project "${name}"`);
|
|
279
463
|
console.log('');
|
|
280
464
|
console.log(' Created:');
|
|
281
465
|
console.log(` src/main.cpp — app shell (GLFW + OpenGL + ImGui)`);
|
|
282
466
|
console.log(` src/App.tsx — your root component`);
|
|
283
|
-
console.log(` src/
|
|
467
|
+
console.log(` src/imx.d.ts — type definitions for IDE support`);
|
|
284
468
|
console.log(` tsconfig.json — TypeScript config`);
|
|
285
469
|
console.log(` CMakeLists.txt — build config with FetchContent`);
|
|
470
|
+
console.log(` public/ — static assets (copied to exe directory)`);
|
|
286
471
|
console.log('');
|
|
287
472
|
console.log(' Next steps:');
|
|
288
473
|
console.log(` cmake -B build`);
|