imxc 0.5.4 → 0.6.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 +8 -0
- package/dist/compile.js +285 -25
- package/dist/components.js +597 -45
- package/dist/diagnostics.js +3 -2
- package/dist/emitter.d.ts +6 -3
- package/dist/emitter.js +1454 -322
- package/dist/index.js +34 -7
- package/dist/init.d.ts +7 -1
- package/dist/init.js +43 -455
- package/dist/ir.d.ts +437 -5
- package/dist/lowering.d.ts +4 -3
- package/dist/lowering.js +770 -57
- package/dist/parser.d.ts +1 -0
- package/dist/templates/async.d.ts +1 -0
- package/dist/templates/async.js +228 -0
- package/dist/templates/custom.d.ts +15 -0
- package/dist/templates/custom.js +945 -0
- package/dist/templates/filedialog.d.ts +1 -0
- package/dist/templates/filedialog.js +216 -0
- package/dist/templates/hotreload.d.ts +1 -0
- package/dist/templates/hotreload.js +400 -0
- package/dist/templates/index.d.ts +16 -0
- package/dist/templates/index.js +553 -0
- package/dist/templates/minimal.d.ts +1 -0
- package/dist/templates/minimal.js +165 -0
- package/dist/templates/networking.d.ts +1 -0
- package/dist/templates/networking.js +244 -0
- package/dist/templates/persistence.d.ts +1 -0
- package/dist/templates/persistence.js +238 -0
- package/dist/validator.d.ts +1 -0
- package/dist/validator.js +51 -22
- package/dist/watch.d.ts +2 -1
- package/dist/watch.js +21 -4
- package/package.json +2 -4
package/dist/parser.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export interface ParseError {
|
|
|
10
10
|
line: number;
|
|
11
11
|
col: number;
|
|
12
12
|
message: string;
|
|
13
|
+
severity?: 'error' | 'warning';
|
|
13
14
|
}
|
|
14
15
|
export declare function parseFile(filePath: string, source: string): ParsedFile;
|
|
15
16
|
export declare function extractImports(sourceFile: ts.SourceFile): Map<string, string>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { registerTemplate, buildImxDts, TSCONFIG, GITIGNORE, cmakeTemplate } from './index.js';
|
|
4
|
+
const APPSTATE_INTERFACE = `interface AppState {
|
|
5
|
+
loading: boolean;
|
|
6
|
+
result: string;
|
|
7
|
+
onFetchData: () => void;
|
|
8
|
+
}`;
|
|
9
|
+
const APPSTATE_H = `#pragma once
|
|
10
|
+
#include <string>
|
|
11
|
+
#include <functional>
|
|
12
|
+
|
|
13
|
+
struct AppState {
|
|
14
|
+
bool loading = false;
|
|
15
|
+
std::string result = "";
|
|
16
|
+
std::function<void()> onFetchData;
|
|
17
|
+
};
|
|
18
|
+
`;
|
|
19
|
+
const ASYNC_H = `#pragma once
|
|
20
|
+
#include <thread>
|
|
21
|
+
#include <functional>
|
|
22
|
+
#include <imx/runtime.h>
|
|
23
|
+
|
|
24
|
+
namespace imx {
|
|
25
|
+
|
|
26
|
+
// Runs \`work\` on a background thread, then calls \`on_done\` with the result.
|
|
27
|
+
// Calls request_frame() so the UI wakes up to display the result.
|
|
28
|
+
// Replace with a thread pool if you need to limit concurrency.
|
|
29
|
+
template<typename T>
|
|
30
|
+
void run_async(Runtime& runtime, std::function<T()> work, std::function<void(T)> on_done) {
|
|
31
|
+
std::thread([&runtime, work = std::move(work), on_done = std::move(on_done)]() {
|
|
32
|
+
T result = work();
|
|
33
|
+
on_done(std::move(result));
|
|
34
|
+
runtime.request_frame();
|
|
35
|
+
}).detach();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
} // namespace imx
|
|
39
|
+
`;
|
|
40
|
+
const MAIN_CPP = `#include <imx/runtime.h>
|
|
41
|
+
#include <imx/renderer.h>
|
|
42
|
+
|
|
43
|
+
#include <imgui.h>
|
|
44
|
+
#include <imgui_impl_glfw.h>
|
|
45
|
+
#include <imgui_impl_opengl3.h>
|
|
46
|
+
#include <GLFW/glfw3.h>
|
|
47
|
+
|
|
48
|
+
#include <thread>
|
|
49
|
+
#include <chrono>
|
|
50
|
+
#include "async.h"
|
|
51
|
+
#include "AppState.h"
|
|
52
|
+
|
|
53
|
+
struct App {
|
|
54
|
+
GLFWwindow* window = nullptr;
|
|
55
|
+
ImGuiIO* io = nullptr;
|
|
56
|
+
imx::Runtime runtime;
|
|
57
|
+
AppState state;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
static void render_frame(App& app) {
|
|
61
|
+
glfwMakeContextCurrent(app.window);
|
|
62
|
+
if (glfwGetWindowAttrib(app.window, GLFW_ICONIFIED) != 0) return;
|
|
63
|
+
|
|
64
|
+
int fb_w = 0, fb_h = 0;
|
|
65
|
+
glfwGetFramebufferSize(app.window, &fb_w, &fb_h);
|
|
66
|
+
if (fb_w <= 0 || fb_h <= 0) return;
|
|
67
|
+
|
|
68
|
+
ImGui_ImplOpenGL3_NewFrame();
|
|
69
|
+
ImGui_ImplGlfw_NewFrame();
|
|
70
|
+
ImGui::NewFrame();
|
|
71
|
+
|
|
72
|
+
imx::render_root(app.runtime, app.state);
|
|
73
|
+
|
|
74
|
+
ImGui::Render();
|
|
75
|
+
glViewport(0, 0, fb_w, fb_h);
|
|
76
|
+
glClearColor(0.12F, 0.12F, 0.15F, 1.0F);
|
|
77
|
+
glClear(GL_COLOR_BUFFER_BIT);
|
|
78
|
+
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
|
79
|
+
|
|
80
|
+
if ((app.io->ConfigFlags & ImGuiConfigFlags_ViewportsEnable) != 0) {
|
|
81
|
+
ImGui::UpdatePlatformWindows();
|
|
82
|
+
ImGui::RenderPlatformWindowsDefault();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
glfwMakeContextCurrent(app.window);
|
|
86
|
+
glfwSwapBuffers(app.window);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
static void window_size_callback(GLFWwindow* window, int, int) {
|
|
90
|
+
auto* app = static_cast<App*>(glfwGetWindowUserPointer(window));
|
|
91
|
+
if (app) render_frame(*app);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
int main() {
|
|
95
|
+
if (glfwInit() == 0) return 1;
|
|
96
|
+
|
|
97
|
+
const char* glsl_version = "#version 150";
|
|
98
|
+
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
99
|
+
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
|
100
|
+
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
101
|
+
#ifdef __APPLE__
|
|
102
|
+
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
|
103
|
+
#endif
|
|
104
|
+
|
|
105
|
+
GLFWwindow* window = glfwCreateWindow(800, 600, "APP_NAME", nullptr, nullptr);
|
|
106
|
+
if (!window) { glfwTerminate(); return 1; }
|
|
107
|
+
glfwMakeContextCurrent(window);
|
|
108
|
+
glfwSwapInterval(1);
|
|
109
|
+
|
|
110
|
+
IMGUI_CHECKVERSION();
|
|
111
|
+
ImGui::CreateContext();
|
|
112
|
+
ImGuiIO& io = ImGui::GetIO();
|
|
113
|
+
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
|
114
|
+
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
|
|
115
|
+
|
|
116
|
+
ImGui::StyleColorsDark();
|
|
117
|
+
ImGuiStyle& style = ImGui::GetStyle();
|
|
118
|
+
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
|
|
119
|
+
style.WindowRounding = 0.0F;
|
|
120
|
+
style.Colors[ImGuiCol_WindowBg].w = 1.0F;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
|
124
|
+
ImGui_ImplOpenGL3_Init(glsl_version);
|
|
125
|
+
|
|
126
|
+
App app;
|
|
127
|
+
app.window = window;
|
|
128
|
+
app.io = &io;
|
|
129
|
+
glfwSetWindowUserPointer(window, &app);
|
|
130
|
+
glfwSetWindowSizeCallback(window, window_size_callback);
|
|
131
|
+
|
|
132
|
+
app.state.onFetchData = [&]() {
|
|
133
|
+
app.state.loading = true;
|
|
134
|
+
app.state.result = "";
|
|
135
|
+
imx::run_async<std::string>(
|
|
136
|
+
app.runtime,
|
|
137
|
+
[]() {
|
|
138
|
+
// Simulate work — replace with real computation
|
|
139
|
+
std::this_thread::sleep_for(std::chrono::seconds(2));
|
|
140
|
+
return std::string("Data loaded successfully!");
|
|
141
|
+
},
|
|
142
|
+
[&](std::string res) {
|
|
143
|
+
app.state.result = std::move(res);
|
|
144
|
+
app.state.loading = false;
|
|
145
|
+
}
|
|
146
|
+
);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
while (glfwWindowShouldClose(window) == 0) {
|
|
150
|
+
if (app.runtime.needs_frame()) {
|
|
151
|
+
glfwPollEvents();
|
|
152
|
+
} else {
|
|
153
|
+
glfwWaitEventsTimeout(0.1);
|
|
154
|
+
}
|
|
155
|
+
render_frame(app);
|
|
156
|
+
app.runtime.frame_rendered(ImGui::IsAnyItemActive());
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
ImGui_ImplOpenGL3_Shutdown();
|
|
160
|
+
ImGui_ImplGlfw_Shutdown();
|
|
161
|
+
ImGui::DestroyContext();
|
|
162
|
+
glfwDestroyWindow(window);
|
|
163
|
+
glfwTerminate();
|
|
164
|
+
return 0;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
#ifdef _WIN32
|
|
168
|
+
#include <windows.h>
|
|
169
|
+
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { return main(); }
|
|
170
|
+
#endif
|
|
171
|
+
`;
|
|
172
|
+
const APP_TSX = `export default function App(props: AppState) {
|
|
173
|
+
return (
|
|
174
|
+
<DockSpace>
|
|
175
|
+
<Window title="Async Demo">
|
|
176
|
+
<Column gap={8}>
|
|
177
|
+
<Text>Background Task Example</Text>
|
|
178
|
+
<Separator />
|
|
179
|
+
<Button
|
|
180
|
+
title="Fetch Data"
|
|
181
|
+
onPress={props.onFetchData}
|
|
182
|
+
disabled={props.loading}
|
|
183
|
+
/>
|
|
184
|
+
{props.loading && <Text color={[1, 0.8, 0, 1]}>Loading...</Text>}
|
|
185
|
+
{props.result !== "" && <Text color={[0, 1, 0, 1]}>Result: {props.result}</Text>}
|
|
186
|
+
</Column>
|
|
187
|
+
</Window>
|
|
188
|
+
</DockSpace>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
`;
|
|
192
|
+
function generate(projectDir, projectName) {
|
|
193
|
+
const srcDir = path.join(projectDir, 'src');
|
|
194
|
+
if (fs.existsSync(path.join(srcDir, 'App.tsx'))) {
|
|
195
|
+
console.error(`Error: ${srcDir}/App.tsx already exists. Aborting.`);
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
198
|
+
fs.mkdirSync(srcDir, { recursive: true });
|
|
199
|
+
const publicDir = path.join(projectDir, 'public');
|
|
200
|
+
fs.mkdirSync(publicDir, { recursive: true });
|
|
201
|
+
// Write files
|
|
202
|
+
fs.writeFileSync(path.join(srcDir, 'main.cpp'), MAIN_CPP.replace('APP_NAME', projectName));
|
|
203
|
+
fs.writeFileSync(path.join(srcDir, 'AppState.h'), APPSTATE_H);
|
|
204
|
+
fs.writeFileSync(path.join(srcDir, 'async.h'), ASYNC_H);
|
|
205
|
+
fs.writeFileSync(path.join(srcDir, 'App.tsx'), APP_TSX);
|
|
206
|
+
fs.writeFileSync(path.join(srcDir, 'imx.d.ts'), buildImxDts(APPSTATE_INTERFACE));
|
|
207
|
+
fs.writeFileSync(path.join(projectDir, 'tsconfig.json'), TSCONFIG);
|
|
208
|
+
fs.writeFileSync(path.join(projectDir, 'CMakeLists.txt'), cmakeTemplate(projectName, 'https://github.com/bgocumlu/imx.git'));
|
|
209
|
+
fs.writeFileSync(path.join(projectDir, '.gitignore'), GITIGNORE);
|
|
210
|
+
console.log(`imxc: initialized project "${projectName}" with template "async"`);
|
|
211
|
+
console.log('');
|
|
212
|
+
console.log(' Created:');
|
|
213
|
+
console.log(` src/main.cpp — app shell with background task setup`);
|
|
214
|
+
console.log(` src/AppState.h — C++ state struct with loading/result fields`);
|
|
215
|
+
console.log(` src/async.h — run_async<T> helper (std::thread + request_frame)`);
|
|
216
|
+
console.log(` src/App.tsx — your root component`);
|
|
217
|
+
console.log(` src/imx.d.ts — type definitions for IDE support`);
|
|
218
|
+
console.log(` tsconfig.json — TypeScript config`);
|
|
219
|
+
console.log(` CMakeLists.txt — build config with FetchContent`);
|
|
220
|
+
console.log(` .gitignore — ignores build/, node_modules/, *.ini`);
|
|
221
|
+
console.log(` public/ — static assets (copied to exe directory)`);
|
|
222
|
+
console.log('');
|
|
223
|
+
console.log(' Next steps:');
|
|
224
|
+
console.log(` cd ${projectName}`);
|
|
225
|
+
console.log(` cmake -B build`);
|
|
226
|
+
console.log(` cmake --build build`);
|
|
227
|
+
}
|
|
228
|
+
registerTemplate({ name: 'async', description: 'Background tasks with std::thread', generate });
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface FeatureModule {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
requires?: string[];
|
|
5
|
+
includes: string[];
|
|
6
|
+
appStateCppFields: string;
|
|
7
|
+
appStateCppHeaders: string[];
|
|
8
|
+
appStateTsFields: string;
|
|
9
|
+
callbacks: string;
|
|
10
|
+
tsxWindow: string;
|
|
11
|
+
extraFiles: Record<string, string>;
|
|
12
|
+
dataFields?: string[];
|
|
13
|
+
}
|
|
14
|
+
export declare const FEATURES: FeatureModule[];
|
|
15
|
+
export declare function generateCombined(featureNames: string[], projectDir: string, projectName: string): void;
|