plusui-native 0.2.68 → 0.2.69
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/package.json +4 -4
- package/src/doctor/detectors/compiler.js +16 -20
- package/src/index.js +71 -56
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plusui-native",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.69",
|
|
4
4
|
"description": "PlusUI CLI - Build C++ desktop apps modern UI ",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"semver": "^7.6.0",
|
|
28
28
|
"which": "^4.0.0",
|
|
29
29
|
"execa": "^8.0.1",
|
|
30
|
-
"plusui-native-builder": "^0.1.
|
|
31
|
-
"plusui-native-connect": "^0.1.
|
|
30
|
+
"plusui-native-builder": "^0.1.68",
|
|
31
|
+
"plusui-native-connect": "^0.1.68"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
|
-
"plusui-native-connect": "^0.1.
|
|
34
|
+
"plusui-native-connect": "^0.1.68"
|
|
35
35
|
},
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public"
|
|
@@ -19,25 +19,21 @@ async function detectMSVC() {
|
|
|
19
19
|
const vswherePath = 'C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\vswhere.exe';
|
|
20
20
|
|
|
21
21
|
if (!existsSync(vswherePath)) {
|
|
22
|
-
// Fallback: check common VS paths
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
name: version,
|
|
38
|
-
path: vsPath,
|
|
39
|
-
valid: true
|
|
40
|
-
};
|
|
22
|
+
// Fallback: check common VS paths for years 2019–2026
|
|
23
|
+
const vsYears = ['2026', '2025', '2024', '2023', '2022', '2019'];
|
|
24
|
+
const vsEditions = ['Community', 'Professional', 'Enterprise', 'BuildTools'];
|
|
25
|
+
|
|
26
|
+
for (const year of vsYears) {
|
|
27
|
+
for (const edition of vsEditions) {
|
|
28
|
+
const vsPath = `C:\\Program Files\\Microsoft Visual Studio\\${year}\\${edition}\\VC\\Tools\\MSVC`;
|
|
29
|
+
if (existsSync(vsPath)) {
|
|
30
|
+
return {
|
|
31
|
+
found: true,
|
|
32
|
+
name: `Visual Studio ${year} ${edition}`,
|
|
33
|
+
path: vsPath,
|
|
34
|
+
valid: true
|
|
35
|
+
};
|
|
36
|
+
}
|
|
41
37
|
}
|
|
42
38
|
}
|
|
43
39
|
|
|
@@ -95,7 +91,7 @@ async function detectXcode() {
|
|
|
95
91
|
|
|
96
92
|
// Parse clang version
|
|
97
93
|
const versionMatch = clangResult.output.match(/clang version (\d+\.\d+\.\d+)/i) ||
|
|
98
|
-
|
|
94
|
+
clangResult.output.match(/Apple clang version (\d+\.\d+\.\d+)/i);
|
|
99
95
|
const version = versionMatch ? versionMatch[1] : 'unknown';
|
|
100
96
|
|
|
101
97
|
return {
|
package/src/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { mkdir, readFile, stat, rm, readdir, writeFile, copyFile } from 'fs/promises';
|
|
4
4
|
import { existsSync, watch, statSync, mkdirSync } from 'fs';
|
|
@@ -74,23 +74,38 @@ function checkTools() {
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
// Compiler / build tools check
|
|
77
78
|
if (platform === 'win32') {
|
|
78
|
-
|
|
79
|
-
'C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC',
|
|
80
|
-
'C:\\Program Files\\Microsoft Visual Studio\\2022\\Professional\\VC\\Tools\\MSVC',
|
|
81
|
-
'C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC'
|
|
82
|
-
];
|
|
83
|
-
|
|
79
|
+
// Use vswhere.exe first (same detection as `plusui doctor`)
|
|
84
80
|
let vsFound = false;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
81
|
+
const vswherePath = 'C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\vswhere.exe';
|
|
82
|
+
if (existsSync(vswherePath)) {
|
|
83
|
+
try {
|
|
84
|
+
const output = execSync(
|
|
85
|
+
`"${vswherePath}" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`,
|
|
86
|
+
{ stdio: ['pipe', 'pipe', 'pipe'], encoding: 'utf8', timeout: 10000 }
|
|
87
|
+
).trim();
|
|
88
|
+
if (output) vsFound = true;
|
|
89
|
+
} catch { }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Fallback: check common VS paths for years 2019–2026
|
|
93
|
+
if (!vsFound) {
|
|
94
|
+
const vsYears = ['2026', '2025', '2024', '2023', '2022', '2019'];
|
|
95
|
+
const vsEditions = ['Community', 'Professional', 'Enterprise', 'BuildTools'];
|
|
96
|
+
for (const year of vsYears) {
|
|
97
|
+
for (const edition of vsEditions) {
|
|
98
|
+
if (existsSync(`C:\\Program Files\\Microsoft Visual Studio\\${year}\\${edition}\\VC\\Tools\\MSVC`)) {
|
|
99
|
+
vsFound = true;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (vsFound) break;
|
|
89
104
|
}
|
|
90
105
|
}
|
|
91
106
|
|
|
92
107
|
if (!vsFound) {
|
|
93
|
-
required.push({ name: 'Visual Studio
|
|
108
|
+
required.push({ name: 'Visual Studio (C++ workload)', install: 'Download from visualstudio.microsoft.com with C++ workload', auto: null });
|
|
94
109
|
}
|
|
95
110
|
} else if (platform === 'darwin') {
|
|
96
111
|
try {
|
|
@@ -203,9 +218,9 @@ function runCMake(args, options = {}) {
|
|
|
203
218
|
|
|
204
219
|
function getInstalledPackageVersion(packageName) {
|
|
205
220
|
try {
|
|
206
|
-
const result = execSync(`npm list ${packageName} --depth=0 --json`, {
|
|
207
|
-
encoding: 'utf8',
|
|
208
|
-
stdio: ['pipe', 'pipe', 'ignore']
|
|
221
|
+
const result = execSync(`npm list ${packageName} --depth=0 --json`, {
|
|
222
|
+
encoding: 'utf8',
|
|
223
|
+
stdio: ['pipe', 'pipe', 'ignore']
|
|
209
224
|
});
|
|
210
225
|
const json = JSON.parse(result);
|
|
211
226
|
if (json.dependencies && json.dependencies[packageName]) {
|
|
@@ -214,12 +229,12 @@ function getInstalledPackageVersion(packageName) {
|
|
|
214
229
|
} catch {
|
|
215
230
|
// Package not installed locally
|
|
216
231
|
}
|
|
217
|
-
|
|
232
|
+
|
|
218
233
|
// Try global installation
|
|
219
234
|
try {
|
|
220
|
-
const result = execSync(`npm list -g ${packageName} --depth=0 --json`, {
|
|
221
|
-
encoding: 'utf8',
|
|
222
|
-
stdio: ['pipe', 'pipe', 'ignore']
|
|
235
|
+
const result = execSync(`npm list -g ${packageName} --depth=0 --json`, {
|
|
236
|
+
encoding: 'utf8',
|
|
237
|
+
stdio: ['pipe', 'pipe', 'ignore']
|
|
223
238
|
});
|
|
224
239
|
const json = JSON.parse(result);
|
|
225
240
|
if (json.dependencies && json.dependencies[packageName]) {
|
|
@@ -228,15 +243,15 @@ function getInstalledPackageVersion(packageName) {
|
|
|
228
243
|
} catch {
|
|
229
244
|
return null;
|
|
230
245
|
}
|
|
231
|
-
|
|
246
|
+
|
|
232
247
|
return null;
|
|
233
248
|
}
|
|
234
249
|
|
|
235
250
|
function getLatestPackageVersion(packageName) {
|
|
236
251
|
try {
|
|
237
|
-
const result = execSync(`npm view ${packageName} version`, {
|
|
238
|
-
encoding: 'utf8',
|
|
239
|
-
stdio: ['pipe', 'pipe', 'ignore']
|
|
252
|
+
const result = execSync(`npm view ${packageName} version`, {
|
|
253
|
+
encoding: 'utf8',
|
|
254
|
+
stdio: ['pipe', 'pipe', 'ignore']
|
|
240
255
|
});
|
|
241
256
|
return result.trim();
|
|
242
257
|
} catch {
|
|
@@ -247,7 +262,7 @@ function getLatestPackageVersion(packageName) {
|
|
|
247
262
|
function compareVersions(v1, v2) {
|
|
248
263
|
const parts1 = v1.split('.').map(Number);
|
|
249
264
|
const parts2 = v2.split('.').map(Number);
|
|
250
|
-
|
|
265
|
+
|
|
251
266
|
for (let i = 0; i < 3; i++) {
|
|
252
267
|
if (parts1[i] > parts2[i]) return 1;
|
|
253
268
|
if (parts1[i] < parts2[i]) return -1;
|
|
@@ -262,9 +277,9 @@ function showVersionInfo() {
|
|
|
262
277
|
'plusui-native-builder',
|
|
263
278
|
'plusui-native-connect'
|
|
264
279
|
];
|
|
265
|
-
|
|
280
|
+
|
|
266
281
|
logSection('PlusUI Package Versions');
|
|
267
|
-
|
|
282
|
+
|
|
268
283
|
packages.forEach(pkg => {
|
|
269
284
|
let version;
|
|
270
285
|
if (pkg === cliPackageJson.name) {
|
|
@@ -279,33 +294,33 @@ function showVersionInfo() {
|
|
|
279
294
|
}
|
|
280
295
|
}
|
|
281
296
|
});
|
|
282
|
-
|
|
297
|
+
|
|
283
298
|
console.log('');
|
|
284
299
|
}
|
|
285
300
|
|
|
286
301
|
async function updatePlusUIPackages() {
|
|
287
302
|
logSection('Updating PlusUI Packages');
|
|
288
|
-
|
|
303
|
+
|
|
289
304
|
const packages = [
|
|
290
305
|
cliPackageJson.name,
|
|
291
306
|
'plusui-native-core',
|
|
292
307
|
'plusui-native-builder',
|
|
293
308
|
'plusui-native-connect'
|
|
294
309
|
];
|
|
295
|
-
|
|
310
|
+
|
|
296
311
|
log('Checking for updates...\n', 'blue');
|
|
297
|
-
|
|
312
|
+
|
|
298
313
|
// Check if packages are installed locally or globally
|
|
299
314
|
const isInProject = existsSync(join(process.cwd(), 'package.json'));
|
|
300
|
-
|
|
315
|
+
|
|
301
316
|
if (isInProject) {
|
|
302
317
|
let updatedCount = 0;
|
|
303
318
|
let upToDateCount = 0;
|
|
304
319
|
let installedCount = 0;
|
|
305
|
-
|
|
320
|
+
|
|
306
321
|
for (const pkg of packages) {
|
|
307
322
|
const currentVersion = getInstalledPackageVersion(pkg);
|
|
308
|
-
|
|
323
|
+
|
|
309
324
|
if (!currentVersion) {
|
|
310
325
|
const latestVersion = getLatestPackageVersion(pkg);
|
|
311
326
|
|
|
@@ -327,22 +342,22 @@ async function updatePlusUIPackages() {
|
|
|
327
342
|
}
|
|
328
343
|
continue;
|
|
329
344
|
}
|
|
330
|
-
|
|
345
|
+
|
|
331
346
|
// Get latest version from npm
|
|
332
347
|
const latestVersion = getLatestPackageVersion(pkg);
|
|
333
|
-
|
|
348
|
+
|
|
334
349
|
if (!latestVersion) {
|
|
335
350
|
log(`${COLORS.yellow}${pkg}: couldn't check for updates${COLORS.reset}`);
|
|
336
351
|
continue;
|
|
337
352
|
}
|
|
338
|
-
|
|
353
|
+
|
|
339
354
|
const comparison = compareVersions(latestVersion, currentVersion);
|
|
340
|
-
|
|
355
|
+
|
|
341
356
|
if (comparison > 0) {
|
|
342
357
|
// Newer version available
|
|
343
358
|
try {
|
|
344
359
|
log(`${COLORS.blue}${pkg}: ${currentVersion} → ${latestVersion}${COLORS.reset}`);
|
|
345
|
-
execSync(`npm install ${pkg}@${latestVersion}`, {
|
|
360
|
+
execSync(`npm install ${pkg}@${latestVersion}`, {
|
|
346
361
|
stdio: ['ignore', 'ignore', 'pipe'],
|
|
347
362
|
encoding: 'utf8'
|
|
348
363
|
});
|
|
@@ -357,7 +372,7 @@ async function updatePlusUIPackages() {
|
|
|
357
372
|
upToDateCount++;
|
|
358
373
|
}
|
|
359
374
|
}
|
|
360
|
-
|
|
375
|
+
|
|
361
376
|
console.log('');
|
|
362
377
|
if (updatedCount > 0) {
|
|
363
378
|
log(`Updated ${updatedCount} package${updatedCount !== 1 ? 's' : ''}`, 'green');
|
|
@@ -370,17 +385,17 @@ async function updatePlusUIPackages() {
|
|
|
370
385
|
}
|
|
371
386
|
} else {
|
|
372
387
|
log('Updating global CLI package...', 'cyan');
|
|
373
|
-
|
|
388
|
+
|
|
374
389
|
const currentVersion = cliPackageJson.version;
|
|
375
390
|
const latestVersion = getLatestPackageVersion(cliPackageJson.name);
|
|
376
|
-
|
|
391
|
+
|
|
377
392
|
if (!latestVersion) {
|
|
378
393
|
log('Couldn\'t check for updates', 'yellow');
|
|
379
394
|
return;
|
|
380
395
|
}
|
|
381
|
-
|
|
396
|
+
|
|
382
397
|
const comparison = compareVersions(latestVersion, currentVersion);
|
|
383
|
-
|
|
398
|
+
|
|
384
399
|
if (comparison > 0) {
|
|
385
400
|
try {
|
|
386
401
|
log(`${COLORS.blue}${cliPackageJson.name}: ${currentVersion} → ${latestVersion}${COLORS.reset}`);
|
|
@@ -393,7 +408,7 @@ async function updatePlusUIPackages() {
|
|
|
393
408
|
log(`✓ ${cliPackageJson.name} v${currentVersion} (already up to date)`, 'green');
|
|
394
409
|
}
|
|
395
410
|
}
|
|
396
|
-
|
|
411
|
+
|
|
397
412
|
console.log('');
|
|
398
413
|
}
|
|
399
414
|
|
|
@@ -411,7 +426,7 @@ function findLikelyProjectDirs(baseDir) {
|
|
|
411
426
|
if (entries) {
|
|
412
427
|
// noop; just to ensure cwd is a Node project when possible
|
|
413
428
|
}
|
|
414
|
-
} catch {}
|
|
429
|
+
} catch { }
|
|
415
430
|
|
|
416
431
|
const candidates = [];
|
|
417
432
|
try {
|
|
@@ -431,7 +446,7 @@ function findLikelyProjectDirs(baseDir) {
|
|
|
431
446
|
candidates.push(dirName);
|
|
432
447
|
}
|
|
433
448
|
}
|
|
434
|
-
} catch {}
|
|
449
|
+
} catch { }
|
|
435
450
|
|
|
436
451
|
return candidates;
|
|
437
452
|
}
|
|
@@ -645,30 +660,30 @@ async function embedAssets() {
|
|
|
645
660
|
if (!existsSync(assetsDir)) {
|
|
646
661
|
try {
|
|
647
662
|
await mkdir(assetsDir, { recursive: true });
|
|
648
|
-
} catch(e) {}
|
|
663
|
+
} catch (e) { }
|
|
649
664
|
}
|
|
650
665
|
|
|
651
666
|
logSection('Embedding Assets');
|
|
652
|
-
|
|
667
|
+
|
|
653
668
|
// Always generate the header file, even if empty
|
|
654
669
|
let headerContent = '#pragma once\n\n';
|
|
655
670
|
headerContent += '// THIS FILE IS AUTO-GENERATED BY PLUSUI CLI\n';
|
|
656
671
|
headerContent += '// DO NOT MODIFY MANUALLY\n\n';
|
|
657
|
-
|
|
658
|
-
const files = existsSync(assetsDir)
|
|
672
|
+
|
|
673
|
+
const files = existsSync(assetsDir)
|
|
659
674
|
? (await readdir(assetsDir)).filter(f => !statSync(join(assetsDir, f)).isDirectory())
|
|
660
675
|
: [];
|
|
661
|
-
|
|
676
|
+
|
|
662
677
|
if (files.length === 0) {
|
|
663
678
|
log('No assets found in assets/ folder', 'dim');
|
|
664
679
|
} else {
|
|
665
680
|
for (const file of files) {
|
|
666
681
|
const filePath = join(assetsDir, file);
|
|
667
682
|
log(`Processing ${file}...`, 'dim');
|
|
668
|
-
|
|
683
|
+
|
|
669
684
|
const varName = file.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase();
|
|
670
685
|
const data = await readFile(filePath);
|
|
671
|
-
|
|
686
|
+
|
|
672
687
|
headerContent += `static const unsigned char ASSET_${varName}[] = {`;
|
|
673
688
|
for (let i = 0; i < data.length; i++) {
|
|
674
689
|
if (i % 16 === 0) headerContent += '\n ';
|
|
@@ -681,7 +696,7 @@ async function embedAssets() {
|
|
|
681
696
|
|
|
682
697
|
const genDir = join(process.cwd(), 'generated');
|
|
683
698
|
if (!existsSync(genDir)) await mkdir(genDir, { recursive: true });
|
|
684
|
-
|
|
699
|
+
|
|
685
700
|
await writeFile(join(genDir, 'assets.h'), headerContent);
|
|
686
701
|
log(`✓ Assets header generated: generated/assets.h`, 'green');
|
|
687
702
|
}
|
|
@@ -828,7 +843,7 @@ async function killPort(port) {
|
|
|
828
843
|
try {
|
|
829
844
|
const output = execSync(`netstat -ano | findstr :${port}`, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
830
845
|
const lines = output.split('\n').filter(line => line.includes(`:${port}`) && line.includes('LISTENING'));
|
|
831
|
-
|
|
846
|
+
|
|
832
847
|
for (const line of lines) {
|
|
833
848
|
const parts = line.trim().split(/\s+/);
|
|
834
849
|
const pid = parts[parts.length - 1];
|
|
@@ -1097,7 +1112,7 @@ async function runBindgen(providedArgs = null, options = {}) {
|
|
|
1097
1112
|
defaultOutputDir = appOutputDir;
|
|
1098
1113
|
log(`Project mode: ${process.cwd()} -> ${appOutputDir}`, 'dim');
|
|
1099
1114
|
}
|
|
1100
|
-
|
|
1115
|
+
|
|
1101
1116
|
// Spawn node process
|
|
1102
1117
|
const proc = spawn(process.execPath, [scriptPath, ...bindgenArgs], {
|
|
1103
1118
|
stdio: 'inherit',
|