windowpp 0.1.1 → 0.1.2

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 (2) hide show
  1. package/lib/create.js +95 -283
  2. package/package.json +1 -1
package/lib/create.js CHANGED
@@ -1,283 +1,95 @@
1
- #!/usr/bin/env node
2
- // cli/lib/create.js — WindowPP app scaffolding
3
- //
4
- // Copies a template from cli/templates/<template>/ to <outDir>/<name>/,
5
- // substituting {{APP_NAME}}, {{APP_TITLE}}, and {{CMAKE_TARGET}} in all
6
- // text files. Each created app is a self-contained project; it does NOT
7
- // need to live inside the framework repo.
8
- //
9
- // Usage (via CLI):
10
- // windowpp create my-app [--template solid] [--out-dir .]
11
-
12
- 'use strict';
13
-
14
- const path = require('path');
15
- const fs = require('fs');
16
- const { execSync } = require('child_process');
17
-
18
- function create(name, options = {}) {
19
- const {
20
- template = 'solid',
21
- outDir = process.cwd(),
22
- installDeps = true,
23
- } = options;
24
-
25
- if (!name || !/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name)) {
26
- console.error('Error: app name must start with a letter and contain only letters, digits, hyphens or underscores.');
27
- process.exit(1);
28
- }
29
-
30
- const appDir = path.join(outDir, name);
31
- if (fs.existsSync(appDir)) {
32
- console.error(`Error: directory "${appDir}" already exists.`);
33
- process.exit(1);
34
- }
35
-
36
- const cliDir = path.resolve(__dirname, '..');
37
- const templateDir = path.join(cliDir, 'templates', template);
38
- if (!fs.existsSync(templateDir)) {
39
- console.error(`Error: template "${template}" not found in ${path.join(cliDir, 'templates')}`);
40
- process.exit(1);
41
- }
42
-
43
- const cmakeTarget = name.replace(/-/g, '_');
44
- const appTitle = name
45
- .split(/[-_]/)
46
- .map(w => w.charAt(0).toUpperCase() + w.slice(1))
47
- .join(' ');
48
-
49
- const tokens = {
50
- '{{APP_NAME}}': name,
51
- '{{APP_TITLE}}': appTitle,
52
- '{{CMAKE_TARGET}}': cmakeTarget,
53
- };
54
-
55
- console.log(`\n=== WindowPP Create — ${name} (template: ${template}) ===\n`);
56
- console.log(`Scaffolding into: ${appDir}\n`);
57
-
58
- // ── Copy template ─────────────────────────────────────────────────────────
59
- copyDir(templateDir, appDir, tokens);
60
-
61
- // ── Install frontend deps ─────────────────────────────────────────────────
62
- const frontendDir = path.join(appDir, 'frontend');
63
- if (installDeps && fs.existsSync(frontendDir)) {
64
- console.log('Installing frontend dependencies...');
65
- execSync('npm install', { cwd: frontendDir, stdio: 'inherit' });
66
- }
67
-
68
- console.log(`\n✓ Created "${name}"\n`);
69
- console.log('Next steps:');
70
- console.log(` cd ${name}`);
71
- console.log(' windowpp dev\n');
72
- }
73
-
74
- // ── Helpers ───────────────────────────────────────────────────────────────────
75
-
76
- function copyDir(src, dest, tokens) {
77
- fs.mkdirSync(dest, { recursive: true });
78
- for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
79
- const srcPath = path.join(src, entry.name);
80
- const destPath = path.join(dest, entry.name);
81
- if (entry.isDirectory()) {
82
- copyDir(srcPath, destPath, tokens);
83
- } else {
84
- copyFile(srcPath, destPath, tokens);
85
- }
86
- }
87
- }
88
-
89
- const TEXT_EXTENSIONS = new Set([
90
- '.cpp', '.h', '.ts', '.tsx', '.js', '.json', '.html',
91
- '.css', '.md', '.txt', '.cmake', '.sh', '.env',
92
- ]);
93
-
94
- function copyFile(src, dest, tokens) {
95
- const ext = path.extname(src).toLowerCase();
96
- if (TEXT_EXTENSIONS.has(ext)) {
97
- let content = fs.readFileSync(src, 'utf8');
98
- for (const [token, value] of Object.entries(tokens)) {
99
- content = content.split(token).join(value);
100
- }
101
- fs.writeFileSync(dest, content, 'utf8');
102
- } else {
103
- fs.copyFileSync(src, dest);
104
- }
105
- }
106
-
107
- module.exports = { create };
108
-
109
-
110
- function create(name, options = {}) {
111
- const {
112
- template = 'solid',
113
- outDir = process.cwd(),
114
- installDeps = true,
115
- } = options;
116
-
117
- if (!name || !/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name)) {
118
- console.error('Error: app name must start with a letter and contain only letters, digits, hyphens or underscores.');
119
- process.exit(1);
120
- }
121
-
122
- const appDir = path.join(outDir, name);
123
- if (fs.existsSync(appDir)) {
124
- console.error(`Error: directory "${appDir}" already exists.`);
125
- process.exit(1);
126
- }
127
-
128
- const cliDir = path.resolve(__dirname, '..');
129
- const templateDir = path.join(cliDir, 'templates', template);
130
- if (!fs.existsSync(templateDir)) {
131
- console.error(`Error: template "${template}" not found in ${path.join(cliDir, 'templates')}`);
132
- process.exit(1);
133
- }
134
-
135
- const rootDir = findRootDir(outDir);
136
-
137
- // cmake target name: replace hyphens with underscores
138
- const cmakeTarget = name.replace(/-/g, '_');
139
- const appTitle = name
140
- .split(/[-_]/)
141
- .map(w => w.charAt(0).toUpperCase() + w.slice(1))
142
- .join(' ');
143
-
144
- const tokens = {
145
- '{{APP_NAME}}': name,
146
- '{{APP_TITLE}}': appTitle,
147
- '{{CMAKE_TARGET}}': cmakeTarget,
148
- '{{REPO_ROOT}}': rootDir.replace(/\\/g, '/'),
149
- };
150
-
151
- console.log(`\n=== WindowPP Create — ${name} (template: ${template}) ===\n`);
152
- console.log(`Scaffolding into: ${appDir}\n`);
153
-
154
- // ── Copy template ─────────────────────────────────────────────────────────
155
- copyDir(templateDir, appDir, tokens);
156
-
157
- // ── Register in CMakeLists.txt ────────────────────────────────────────────
158
- const appDirRelative = path.relative(rootDir, appDir).replace(/\\/g, '/');
159
- addToCMake(rootDir, name, cmakeTarget, appDirRelative);
160
-
161
- // ── Install frontend deps ─────────────────────────────────────────────────
162
- const frontendDir = path.join(appDir, 'frontend');
163
- if (installDeps && fs.existsSync(frontendDir)) {
164
- console.log('Installing frontend dependencies...');
165
- execSync('npm install', { cwd: frontendDir, stdio: 'inherit' });
166
- }
167
-
168
- console.log(`\n✓ Created "${name}"\n`);
169
- console.log('Next steps:');
170
- console.log(` cd ${name}`);
171
- console.log(' windowpp dev\n');
172
- }
173
-
174
- // ── Helpers ───────────────────────────────────────────────────────────────────
175
-
176
- function copyDir(src, dest, tokens) {
177
- fs.mkdirSync(dest, { recursive: true });
178
- for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
179
- const srcPath = path.join(src, entry.name);
180
- const destPath = path.join(dest, entry.name);
181
- if (entry.isDirectory()) {
182
- copyDir(srcPath, destPath, tokens);
183
- } else {
184
- copyFile(srcPath, destPath, tokens);
185
- }
186
- }
187
- }
188
-
189
- const TEXT_EXTENSIONS = new Set([
190
- '.cpp', '.h', '.ts', '.tsx', '.js', '.json', '.html',
191
- '.css', '.md', '.txt', '.cmake', '.sh', '.env',
192
- ]);
193
-
194
- function copyFile(src, dest, tokens) {
195
- const ext = path.extname(src).toLowerCase();
196
- if (TEXT_EXTENSIONS.has(ext)) {
197
- let content = fs.readFileSync(src, 'utf8');
198
- for (const [token, value] of Object.entries(tokens)) {
199
- content = content.split(token).join(value);
200
- }
201
- fs.writeFileSync(dest, content, 'utf8');
202
- } else {
203
- fs.copyFileSync(src, dest);
204
- }
205
- }
206
-
207
- function addToCMake(rootDir, appName, cmakeTarget, appDirRelative) {
208
- const cmakePath = path.join(rootDir, 'CMakeLists.txt');
209
- let cmake = fs.readFileSync(cmakePath, 'utf8');
210
-
211
- // Insert before the # ─── Install section
212
- const installMarker = '# ─── Install ──';
213
- if (!cmake.includes(installMarker)) {
214
- console.warn('Warning: could not locate Install section in CMakeLists.txt — skipping auto-registration.');
215
- return;
216
- }
217
-
218
- const appBlock = generateCMakeBlock(appName, cmakeTarget, appDirRelative);
219
- cmake = cmake.replace(installMarker, appBlock + '\n' + installMarker);
220
- fs.writeFileSync(cmakePath, cmake, 'utf8');
221
- console.log(`Registered ${cmakeTarget} in CMakeLists.txt`);
222
- }
223
-
224
- function generateCMakeBlock(appName, cmakeTarget, appDirRelative) {
225
- const generatedVar = cmakeTarget.toUpperCase() + '_GENERATED_DIR';
226
- const embeddedCppVar = cmakeTarget.toUpperCase() + '_EMBEDDED_ASSETS_CPP';
227
- const embeddedHVar = cmakeTarget.toUpperCase() + '_EMBEDDED_ASSETS_H';
228
- const assetsTarget = cmakeTarget + '_frontend_assets';
229
-
230
- return `# ─── ${appName} ──────────────────────────────────────────────────────────────────
231
-
232
- if(WPP_BUILD_EXAMPLES)
233
- add_executable(${cmakeTarget} ${appDirRelative}/main.cpp)
234
- target_link_libraries(${cmakeTarget} PRIVATE windowpp nlohmann_json::nlohmann_json)
235
- if(WIN32 AND WEBVIEW2_INCLUDE_DIR)
236
- target_include_directories(${cmakeTarget} PRIVATE \${WEBVIEW2_INCLUDE_DIR})
237
- if(WEBVIEW2_STATIC)
238
- target_link_libraries(${cmakeTarget} PRIVATE
239
- \${CMAKE_CURRENT_SOURCE_DIR}/src/renderer/webview/x64/WebView2LoaderStatic.lib
240
- version)
241
- else()
242
- target_link_libraries(${cmakeTarget} PRIVATE
243
- \${CMAKE_CURRENT_SOURCE_DIR}/src/renderer/webview/x64/WebView2Loader.lib)
244
- endif()
245
- endif()
246
-
247
- set(${generatedVar} \${CMAKE_BINARY_DIR}/generated_${cmakeTarget})
248
- set(${embeddedCppVar} \${${generatedVar}}/embedded_assets.cpp)
249
- set(${embeddedHVar} \${${generatedVar}}/embedded_assets.h)
250
-
251
- add_custom_command(
252
- OUTPUT \${${embeddedCppVar}} \${${embeddedHVar}}
253
- COMMAND \${CMAKE_COMMAND} -E make_directory \${${generatedVar}}
254
- COMMAND \${Python3_EXECUTABLE}
255
- \${WPP_EMBED_SCRIPT}
256
- \${CMAKE_CURRENT_SOURCE_DIR}/${appDirRelative}/frontend/dist
257
- \${${embeddedCppVar}}
258
- \${${embeddedHVar}}
259
- DEPENDS \${CMAKE_CURRENT_SOURCE_DIR}/${appDirRelative}/frontend/dist/index.html
260
- COMMENT "Embedding ${appName} frontend assets into C++ byte arrays..."
261
- VERBATIM
262
- )
263
-
264
- set_source_files_properties(
265
- \${${embeddedCppVar}}
266
- \${${embeddedHVar}}
267
- PROPERTIES GENERATED TRUE
268
- )
269
-
270
- add_custom_target(${assetsTarget} ALL
271
- DEPENDS \${${embeddedCppVar}} \${${embeddedHVar}}
272
- )
273
-
274
- target_sources(${cmakeTarget} PRIVATE \${${embeddedCppVar}})
275
- target_include_directories(${cmakeTarget} PRIVATE \${${generatedVar}})
276
- target_compile_definitions(${cmakeTarget} PRIVATE WPP_EMBEDDED_ASSETS)
277
- add_dependencies(${cmakeTarget} ${assetsTarget})
278
- endif()
279
-
280
- `;
281
- }
282
-
283
- module.exports = { create };
1
+ #!/usr/bin/env node
2
+ // cli/lib/create.js — WindowPP app scaffolding
3
+
4
+ 'use strict';
5
+
6
+ const path = require('path');
7
+ const fs = require('fs');
8
+ const { execSync } = require('child_process');
9
+
10
+ const TEXT_EXTENSIONS = new Set([
11
+ '.cpp', '.h', '.ts', '.tsx', '.js', '.json', '.html',
12
+ '.css', '.md', '.txt', '.cmake', '.sh', '.env',
13
+ ]);
14
+
15
+ function copyFile(src, dest, tokens) {
16
+ const ext = path.extname(src).toLowerCase();
17
+ if (TEXT_EXTENSIONS.has(ext)) {
18
+ let content = fs.readFileSync(src, 'utf8');
19
+ for (const [token, value] of Object.entries(tokens)) {
20
+ content = content.split(token).join(value);
21
+ }
22
+ fs.writeFileSync(dest, content, 'utf8');
23
+ } else {
24
+ fs.copyFileSync(src, dest);
25
+ }
26
+ }
27
+
28
+ function copyDir(src, dest, tokens) {
29
+ fs.mkdirSync(dest, { recursive: true });
30
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
31
+ const srcPath = path.join(src, entry.name);
32
+ const destPath = path.join(dest, entry.name);
33
+ if (entry.isDirectory()) {
34
+ copyDir(srcPath, destPath, tokens);
35
+ } else {
36
+ copyFile(srcPath, destPath, tokens);
37
+ }
38
+ }
39
+ }
40
+
41
+ function create(name, options = {}) {
42
+ const {
43
+ template = 'solid',
44
+ outDir = process.cwd(),
45
+ installDeps = true,
46
+ } = options;
47
+
48
+ if (!name || !/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name)) {
49
+ console.error('Error: app name must start with a letter and contain only letters, digits, hyphens or underscores.');
50
+ process.exit(1);
51
+ }
52
+
53
+ const appDir = path.join(outDir, name);
54
+ if (fs.existsSync(appDir)) {
55
+ console.error(`Error: directory "${appDir}" already exists.`);
56
+ process.exit(1);
57
+ }
58
+
59
+ const cliDir = path.resolve(__dirname, '..');
60
+ const templateDir = path.join(cliDir, 'templates', template);
61
+ if (!fs.existsSync(templateDir)) {
62
+ console.error(`Error: template "${template}" not found in ${path.join(cliDir, 'templates')}`);
63
+ process.exit(1);
64
+ }
65
+
66
+ const cmakeTarget = name.replace(/-/g, '_');
67
+ const appTitle = name
68
+ .split(/[-_]/)
69
+ .map(w => w.charAt(0).toUpperCase() + w.slice(1))
70
+ .join(' ');
71
+
72
+ const tokens = {
73
+ '{{APP_NAME}}': name,
74
+ '{{APP_TITLE}}': appTitle,
75
+ '{{CMAKE_TARGET}}': cmakeTarget,
76
+ };
77
+
78
+ console.log(`\n=== WindowPP Create --- ${name} (template: ${template}) ===\n`);
79
+ console.log(`Scaffolding into: ${appDir}\n`);
80
+
81
+ copyDir(templateDir, appDir, tokens);
82
+
83
+ const frontendDir = path.join(appDir, 'frontend');
84
+ if (installDeps && fs.existsSync(frontendDir)) {
85
+ console.log('Installing frontend dependencies...');
86
+ execSync('npm install', { cwd: frontendDir, stdio: 'inherit' });
87
+ }
88
+
89
+ console.log(`\n-- Created "${name}"\n`);
90
+ console.log('Next steps:');
91
+ console.log(` cd ${name}`);
92
+ console.log(' windowpp dev\n');
93
+ }
94
+
95
+ module.exports = { create };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "windowpp",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "WindowPP CLI — build, dev, and scaffold for WindowPP apps",
5
5
  "type": "commonjs",
6
6
  "bin": {