create-dev-to 1.3.3 → 1.5.0
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/index.js +210 -71
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,77 +5,97 @@ import { spawn, execSync } from "node:child_process";
|
|
|
5
5
|
import process from "node:process";
|
|
6
6
|
import { randomUUID } from "node:crypto";
|
|
7
7
|
import readline from "node:readline";
|
|
8
|
+
import os from "node:os";
|
|
8
9
|
import * as clack from "@clack/prompts";
|
|
9
10
|
import { red, cyan, yellow, green, dim } from "kolorist";
|
|
10
11
|
import { InstallLogger } from "./installLogger.js";
|
|
11
12
|
import { displayInstallSummary } from "./visualComponents.js";
|
|
12
13
|
const PACKAGE_MANAGERS = ["pnpm", "npm", "yarn", "bun"];
|
|
13
14
|
const __BUILD_INFO__ = {
|
|
14
|
-
commit: "
|
|
15
|
+
commit: "395653e",
|
|
15
16
|
branch: "main",
|
|
16
|
-
buildTime: "2026-01-
|
|
17
|
-
version: "1.
|
|
17
|
+
buildTime: "2026-01-11 02:43",
|
|
18
|
+
version: "1.5.0"
|
|
18
19
|
};
|
|
19
20
|
const FRAMEWORKS = [
|
|
20
21
|
{
|
|
21
22
|
name: "react",
|
|
22
23
|
display: "React",
|
|
23
24
|
color: cyan,
|
|
24
|
-
|
|
25
|
+
variants: [
|
|
26
|
+
{
|
|
27
|
+
name: "react-ts",
|
|
28
|
+
display: "TypeScript",
|
|
29
|
+
color: cyan
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: "react-compiler-ts",
|
|
33
|
+
display: "TypeScript + React Compiler",
|
|
34
|
+
color: cyan
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "react-swc-ts",
|
|
38
|
+
display: "TypeScript + SWC",
|
|
39
|
+
color: cyan
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "react",
|
|
43
|
+
display: "JavaScript",
|
|
44
|
+
color: yellow
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "react-compiler",
|
|
48
|
+
display: "JavaScript + React Compiler",
|
|
49
|
+
color: yellow
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "react-swc",
|
|
53
|
+
display: "JavaScript + SWC",
|
|
54
|
+
color: yellow
|
|
55
|
+
}
|
|
56
|
+
]
|
|
25
57
|
},
|
|
26
58
|
{
|
|
27
59
|
name: "vue",
|
|
28
60
|
display: "Vue",
|
|
29
61
|
color: green,
|
|
30
|
-
|
|
62
|
+
variants: []
|
|
31
63
|
},
|
|
32
64
|
{
|
|
33
65
|
name: "svelte",
|
|
34
66
|
display: "Svelte",
|
|
35
67
|
color: red,
|
|
36
|
-
|
|
68
|
+
variants: []
|
|
37
69
|
},
|
|
38
70
|
{
|
|
39
71
|
name: "solid",
|
|
40
72
|
display: "Solid",
|
|
41
73
|
color: cyan,
|
|
42
|
-
|
|
74
|
+
variants: []
|
|
43
75
|
},
|
|
44
76
|
{
|
|
45
77
|
name: "preact",
|
|
46
78
|
display: "Preact",
|
|
47
79
|
color: cyan,
|
|
48
|
-
|
|
80
|
+
variants: []
|
|
49
81
|
},
|
|
50
82
|
{
|
|
51
83
|
name: "lit",
|
|
52
84
|
display: "Lit",
|
|
53
85
|
color: yellow,
|
|
54
|
-
|
|
86
|
+
variants: []
|
|
55
87
|
},
|
|
56
88
|
{
|
|
57
89
|
name: "qwik",
|
|
58
90
|
display: "Qwik",
|
|
59
91
|
color: cyan,
|
|
60
|
-
|
|
92
|
+
variants: []
|
|
61
93
|
},
|
|
62
94
|
{
|
|
63
95
|
name: "vanilla",
|
|
64
96
|
display: "Vanilla",
|
|
65
97
|
color: yellow,
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
];
|
|
69
|
-
const REACT_TEMPLATES = [
|
|
70
|
-
{
|
|
71
|
-
name: "react-ts",
|
|
72
|
-
display: "TypeScript",
|
|
73
|
-
color: cyan
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
name: "react",
|
|
77
|
-
display: "JavaScript",
|
|
78
|
-
color: yellow
|
|
98
|
+
variants: []
|
|
79
99
|
}
|
|
80
100
|
];
|
|
81
101
|
const TEMPLATE_SOURCES = [
|
|
@@ -235,6 +255,19 @@ function findViteConfigFile(projectDir) {
|
|
|
235
255
|
return null;
|
|
236
256
|
}
|
|
237
257
|
async function cloneViteTemplate(template, targetDir, packageManager, spinner) {
|
|
258
|
+
const cacheMetadata = getTemplateCacheMetadata(template);
|
|
259
|
+
if (cacheMetadata) {
|
|
260
|
+
const shortHash = cacheMetadata.commitHash.slice(0, 8);
|
|
261
|
+
spinner.message(`Checking cache ${dim(`(${shortHash})`)}`);
|
|
262
|
+
const cachedRestored = await restoreFromCache(template, targetDir);
|
|
263
|
+
if (cachedRestored) {
|
|
264
|
+
spinner.stop(`Template restored from cache ${dim(`(${shortHash})`)}`);
|
|
265
|
+
return { fromCache: true, commitHash: cacheMetadata.commitHash };
|
|
266
|
+
}
|
|
267
|
+
spinner.message(`Downloading template ${dim("(cache outdated)")}`);
|
|
268
|
+
} else {
|
|
269
|
+
spinner.message("Downloading template");
|
|
270
|
+
}
|
|
238
271
|
const errors = [];
|
|
239
272
|
for (let i = 0; i < TEMPLATE_SOURCES.length; i++) {
|
|
240
273
|
const source = TEMPLATE_SOURCES[i];
|
|
@@ -243,6 +276,12 @@ async function cloneViteTemplate(template, targetDir, packageManager, spinner) {
|
|
|
243
276
|
if (i > 0) {
|
|
244
277
|
spinner.message(`Trying ${source.name}...`);
|
|
245
278
|
}
|
|
279
|
+
spinner.message(`Checking template version from ${source.name}...`);
|
|
280
|
+
const commitHash = getTemplateCommitHash(source, template);
|
|
281
|
+
if (commitHash) {
|
|
282
|
+
const shortHash = commitHash.slice(0, 8);
|
|
283
|
+
spinner.message(`Latest template version: ${shortHash}`);
|
|
284
|
+
}
|
|
246
285
|
const { command, args } = source.getCloneCommand(template, targetDir, packageManager);
|
|
247
286
|
if (source.isGitBased) {
|
|
248
287
|
const tempCloneDir = path.join(process.cwd(), `.tmp-clone-${randomUUID()}`);
|
|
@@ -274,7 +313,13 @@ async function cloneViteTemplate(template, targetDir, packageManager, spinner) {
|
|
|
274
313
|
} else {
|
|
275
314
|
await run(command, args, process.cwd());
|
|
276
315
|
}
|
|
277
|
-
|
|
316
|
+
if (commitHash) {
|
|
317
|
+
const shortHash = commitHash.slice(0, 8);
|
|
318
|
+
spinner.message(`Caching template ${dim(`(${shortHash})`)} for future use...`);
|
|
319
|
+
await saveToCache(template, targetDir, commitHash);
|
|
320
|
+
spinner.message(`Template cached ${dim(`(${shortHash})`)}`);
|
|
321
|
+
}
|
|
322
|
+
return { fromCache: false, commitHash };
|
|
278
323
|
} catch (error) {
|
|
279
324
|
if (tempTargetDir && fs.existsSync(tempTargetDir)) {
|
|
280
325
|
fs.rmSync(tempTargetDir, { recursive: true, force: true });
|
|
@@ -298,6 +343,7 @@ Please check your network connection or try again later.`
|
|
|
298
343
|
}
|
|
299
344
|
}
|
|
300
345
|
}
|
|
346
|
+
throw new Error("Unexpected end of cloneViteTemplate function");
|
|
301
347
|
}
|
|
302
348
|
function getDegitCommandForPM(pm) {
|
|
303
349
|
switch (pm) {
|
|
@@ -323,6 +369,95 @@ function getDegitCommandForPM(pm) {
|
|
|
323
369
|
};
|
|
324
370
|
}
|
|
325
371
|
}
|
|
372
|
+
function getTemplateCacheDir() {
|
|
373
|
+
const cacheDir = path.join(process.env.HOME || process.env.USERPROFILE || os.homedir(), ".create-dev-to-cache");
|
|
374
|
+
return cacheDir;
|
|
375
|
+
}
|
|
376
|
+
function getTemplateCommitHash(source, template) {
|
|
377
|
+
try {
|
|
378
|
+
if (source.name === "GitHub") {
|
|
379
|
+
const templatePath = `packages/create-vite/template-${template}`;
|
|
380
|
+
const hash = execSync(
|
|
381
|
+
`git ls-remote https://github.com/vitejs/vite.git HEAD | cut -f1`,
|
|
382
|
+
{ stdio: "pipe" }
|
|
383
|
+
).toString().trim();
|
|
384
|
+
try {
|
|
385
|
+
const apiUrl = `https://api.github.com/repos/vitejs/vite/commits?path=${templatePath}&per_page=1`;
|
|
386
|
+
const apiHash = execSync(
|
|
387
|
+
`curl -s "${apiUrl}" | grep -m 1 '"sha"' | cut -d'"' -f4`,
|
|
388
|
+
{ stdio: "pipe" }
|
|
389
|
+
).toString().trim();
|
|
390
|
+
return apiHash || hash;
|
|
391
|
+
} catch {
|
|
392
|
+
return hash;
|
|
393
|
+
}
|
|
394
|
+
} else if (source.name === "Gitee Mirror (\u56FD\u5185\u955C\u50CF)") {
|
|
395
|
+
const hash = execSync("git ls-remote https://gitee.com/mirrors/ViteJS.git HEAD", { stdio: "pipe" }).toString().split(" ")[0].trim();
|
|
396
|
+
return hash;
|
|
397
|
+
} else {
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
} catch {
|
|
401
|
+
return null;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
function getTemplateCachePath(template, commitHash) {
|
|
405
|
+
const cacheDir = getTemplateCacheDir();
|
|
406
|
+
const templateCacheFile = `${template}-${commitHash.slice(0, 8)}.zip`;
|
|
407
|
+
return path.join(cacheDir, templateCacheFile);
|
|
408
|
+
}
|
|
409
|
+
function getTemplateCacheMetadata(template) {
|
|
410
|
+
const cacheDir = getTemplateCacheDir();
|
|
411
|
+
const metadataFile = path.join(cacheDir, `${template}.json`);
|
|
412
|
+
try {
|
|
413
|
+
if (fs.existsSync(metadataFile)) {
|
|
414
|
+
const metadata = JSON.parse(fs.readFileSync(metadataFile, "utf-8"));
|
|
415
|
+
return metadata;
|
|
416
|
+
}
|
|
417
|
+
} catch {
|
|
418
|
+
}
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
421
|
+
function saveTemplateCacheMetadata(template, commitHash) {
|
|
422
|
+
const cacheDir = getTemplateCacheDir();
|
|
423
|
+
if (!fs.existsSync(cacheDir)) {
|
|
424
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
425
|
+
}
|
|
426
|
+
const metadataFile = path.join(cacheDir, `${template}.json`);
|
|
427
|
+
fs.writeFileSync(metadataFile, JSON.stringify({ commitHash }, null, 2));
|
|
428
|
+
}
|
|
429
|
+
async function restoreFromCache(template, targetDir) {
|
|
430
|
+
try {
|
|
431
|
+
const metadata = getTemplateCacheMetadata(template);
|
|
432
|
+
if (!metadata) return false;
|
|
433
|
+
const cachePath = getTemplateCachePath(template, metadata.commitHash);
|
|
434
|
+
const cacheSourceDir = path.join(path.dirname(cachePath), `${template}-${metadata.commitHash.slice(0, 8)}`);
|
|
435
|
+
if (fs.existsSync(cacheSourceDir)) {
|
|
436
|
+
if (fs.existsSync(targetDir)) {
|
|
437
|
+
fs.rmSync(targetDir, { recursive: true, force: true });
|
|
438
|
+
}
|
|
439
|
+
copyDir(cacheSourceDir, targetDir);
|
|
440
|
+
return true;
|
|
441
|
+
}
|
|
442
|
+
} catch {
|
|
443
|
+
}
|
|
444
|
+
return false;
|
|
445
|
+
}
|
|
446
|
+
async function saveToCache(template, sourceDir, commitHash) {
|
|
447
|
+
try {
|
|
448
|
+
const cacheDir = getTemplateCacheDir();
|
|
449
|
+
if (!fs.existsSync(cacheDir)) {
|
|
450
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
451
|
+
}
|
|
452
|
+
const cachePath = getTemplateCachePath(template, commitHash);
|
|
453
|
+
const cacheSourceDir = path.join(path.dirname(cachePath), `${template}-${commitHash.slice(0, 8)}`);
|
|
454
|
+
if (!fs.existsSync(cacheSourceDir)) {
|
|
455
|
+
copyDir(sourceDir, cacheSourceDir);
|
|
456
|
+
}
|
|
457
|
+
saveTemplateCacheMetadata(template, commitHash);
|
|
458
|
+
} catch {
|
|
459
|
+
}
|
|
460
|
+
}
|
|
326
461
|
function injectPluginIntoViteConfig(content, pluginPackage, pluginName) {
|
|
327
462
|
const hasImport = new RegExp(`['"]${pluginPackage.replace(/\//g, "\\/")}['"]`).test(content);
|
|
328
463
|
const hasCall = content.includes(`${pluginName}(`);
|
|
@@ -399,8 +534,16 @@ ${newPlugin}
|
|
|
399
534
|
}
|
|
400
535
|
return out;
|
|
401
536
|
}
|
|
402
|
-
function updatePluginComponentName(content, pluginName, componentName) {
|
|
537
|
+
function updatePluginComponentName(content, pluginName, componentName, projectName) {
|
|
538
|
+
const defaultComponentName = projectName.split(/[-_\s]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
|
|
403
539
|
const pluginCall = `${pluginName}()`;
|
|
540
|
+
if (componentName === defaultComponentName) {
|
|
541
|
+
const newPluginCall2 = `${pluginName}('${componentName}')`;
|
|
542
|
+
if (content.includes(pluginCall)) {
|
|
543
|
+
return content.replace(pluginCall, newPluginCall2);
|
|
544
|
+
}
|
|
545
|
+
return content;
|
|
546
|
+
}
|
|
404
547
|
const newPluginCall = `${pluginName}({
|
|
405
548
|
${componentName}: 'src/${componentName}/index.tsx',
|
|
406
549
|
})`;
|
|
@@ -635,8 +778,8 @@ async function init() {
|
|
|
635
778
|
});
|
|
636
779
|
},
|
|
637
780
|
componentName: ({ results }) => {
|
|
638
|
-
const
|
|
639
|
-
const defaultComponentName =
|
|
781
|
+
const projectName2 = results.projectName || "dev-to-app";
|
|
782
|
+
const defaultComponentName = projectName2.split(/[-_\s]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
|
|
640
783
|
return clack.text({
|
|
641
784
|
message: `First component name ${dim("\n\u2502 Leave blank to default to project name.You can modify it in vite config later.\n")}`,
|
|
642
785
|
placeholder: defaultComponentName,
|
|
@@ -651,7 +794,7 @@ async function init() {
|
|
|
651
794
|
}
|
|
652
795
|
}
|
|
653
796
|
);
|
|
654
|
-
const { shouldOverwrite, componentName } = project;
|
|
797
|
+
const { shouldOverwrite, componentName, projectName } = project;
|
|
655
798
|
if (shouldOverwrite) {
|
|
656
799
|
emptyDir(path.join(cwd, targetDir));
|
|
657
800
|
}
|
|
@@ -669,24 +812,23 @@ async function init() {
|
|
|
669
812
|
}
|
|
670
813
|
packageManager = pmChoice;
|
|
671
814
|
}
|
|
672
|
-
const
|
|
815
|
+
const selectedFramework = await clack.select({
|
|
673
816
|
message: "Select a framework:",
|
|
674
817
|
options: FRAMEWORKS.map((fw) => ({
|
|
675
|
-
value: fw
|
|
676
|
-
label: fw.
|
|
677
|
-
hint: fw.
|
|
818
|
+
value: fw,
|
|
819
|
+
label: fw.variants.length > 0 ? fw.color(fw.display) : `${fw.color(fw.display)} ${dim("(Coming soon)")}`,
|
|
820
|
+
hint: fw.variants.length > 0 ? void 0 : "Not yet supported"
|
|
678
821
|
})),
|
|
679
|
-
initialValue:
|
|
822
|
+
initialValue: FRAMEWORKS[0]
|
|
680
823
|
});
|
|
681
|
-
if (clack.isCancel(
|
|
824
|
+
if (clack.isCancel(selectedFramework)) {
|
|
682
825
|
clack.cancel("Operation cancelled.");
|
|
683
826
|
process.exit(0);
|
|
684
827
|
}
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
clack.outro(yellow(`\u26A0\uFE0F ${selectedFramework?.display} support is coming soon!`));
|
|
828
|
+
if (selectedFramework.variants.length === 0) {
|
|
829
|
+
clack.outro(yellow(`\u26A0\uFE0F ${selectedFramework.display} support is coming soon!`));
|
|
688
830
|
clack.note(
|
|
689
|
-
`We're working hard to add support for ${selectedFramework
|
|
831
|
+
`We're working hard to add support for ${selectedFramework.display}.
|
|
690
832
|
|
|
691
833
|
For now, please use React or stay tuned for updates!`,
|
|
692
834
|
"Roadmap"
|
|
@@ -695,54 +837,40 @@ For now, please use React or stay tuned for updates!`,
|
|
|
695
837
|
}
|
|
696
838
|
const variant = await clack.select({
|
|
697
839
|
message: "Select a variant:",
|
|
698
|
-
options:
|
|
699
|
-
value:
|
|
700
|
-
label:
|
|
840
|
+
options: selectedFramework.variants.map((v) => ({
|
|
841
|
+
value: v.name,
|
|
842
|
+
label: v.color(v.display)
|
|
701
843
|
}))
|
|
702
844
|
});
|
|
703
845
|
if (clack.isCancel(variant)) {
|
|
704
846
|
clack.cancel("Operation cancelled.");
|
|
705
847
|
process.exit(0);
|
|
706
848
|
}
|
|
707
|
-
|
|
708
|
-
const shouldUseSWC = await clack.confirm({
|
|
709
|
-
message: "Use SWC for faster transpilation? (Optional)",
|
|
710
|
-
initialValue: false
|
|
711
|
-
});
|
|
712
|
-
if (clack.isCancel(shouldUseSWC)) {
|
|
713
|
-
clack.cancel("Operation cancelled.");
|
|
714
|
-
process.exit(0);
|
|
715
|
-
}
|
|
716
|
-
const shouldUseReactCompiler = await clack.confirm({
|
|
717
|
-
message: "Use React Compiler? (Experimental)",
|
|
718
|
-
initialValue: false
|
|
719
|
-
});
|
|
720
|
-
if (clack.isCancel(shouldUseReactCompiler)) {
|
|
721
|
-
clack.cancel("Operation cancelled.");
|
|
722
|
-
process.exit(0);
|
|
723
|
-
}
|
|
724
|
-
const shouldUseRolldown = await clack.confirm({
|
|
725
|
-
message: "Use Rolldown for bundling? (Experimental)",
|
|
726
|
-
initialValue: false
|
|
727
|
-
});
|
|
728
|
-
if (clack.isCancel(shouldUseRolldown)) {
|
|
729
|
-
clack.cancel("Operation cancelled.");
|
|
730
|
-
process.exit(0);
|
|
731
|
-
}
|
|
849
|
+
let template = variant;
|
|
732
850
|
const root = path.join(cwd, targetDir);
|
|
733
851
|
const spinner = clack.spinner();
|
|
734
852
|
spinner.start("Scaffolding project");
|
|
735
|
-
|
|
853
|
+
let isReactSwc = false;
|
|
854
|
+
if (template.includes("-swc")) {
|
|
855
|
+
isReactSwc = true;
|
|
856
|
+
template = template.replace("-swc", "");
|
|
857
|
+
}
|
|
858
|
+
let isReactCompiler = false;
|
|
859
|
+
if (template.includes("-compiler")) {
|
|
860
|
+
isReactCompiler = true;
|
|
861
|
+
template = template.replace("-compiler", "");
|
|
862
|
+
}
|
|
863
|
+
const cloneResult = await cloneViteTemplate(template, root, packageManager, spinner);
|
|
736
864
|
const pkgPath = path.join(root, "package.json");
|
|
737
865
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
738
866
|
pkg.name = toValidPackageName(getProjectName());
|
|
739
867
|
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
740
868
|
const isTs = template.includes("ts");
|
|
741
|
-
if (
|
|
869
|
+
if (isReactSwc) {
|
|
742
870
|
spinner.message("Setting up SWC...");
|
|
743
871
|
setupReactSWC(root, isTs);
|
|
744
872
|
}
|
|
745
|
-
if (
|
|
873
|
+
if (isReactCompiler) {
|
|
746
874
|
spinner.message("Setting up React Compiler...");
|
|
747
875
|
setupReactCompiler(root, isTs);
|
|
748
876
|
}
|
|
@@ -754,17 +882,28 @@ For now, please use React or stay tuned for updates!`,
|
|
|
754
882
|
if (viteConfigPath) {
|
|
755
883
|
let patched = fs.readFileSync(viteConfigPath, "utf-8");
|
|
756
884
|
patched = injectPluginIntoViteConfig(patched, pluginPackage, pluginName);
|
|
757
|
-
patched = updatePluginComponentName(patched, pluginName, componentName);
|
|
885
|
+
patched = updatePluginComponentName(patched, pluginName, componentName, projectName);
|
|
758
886
|
fs.writeFileSync(viteConfigPath, patched);
|
|
759
887
|
}
|
|
760
888
|
spinner.message(`Creating component ${componentName}...`);
|
|
761
889
|
createComponentFile(root, componentName, isTs);
|
|
762
|
-
|
|
890
|
+
let completionMessage = "Project created";
|
|
891
|
+
if (cloneResult.commitHash) {
|
|
892
|
+
const shortHash = cloneResult.commitHash.slice(0, 8);
|
|
893
|
+
if (cloneResult.fromCache) {
|
|
894
|
+
completionMessage += ` ${dim(`with cached template (${shortHash})`)}`;
|
|
895
|
+
} else {
|
|
896
|
+
completionMessage += ` ${dim(`(${shortHash})`)}`;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
spinner.stop(completionMessage);
|
|
763
900
|
const shouldInstall = await clack.confirm({
|
|
764
901
|
message: "Install dependencies and start dev server?",
|
|
765
902
|
initialValue: true
|
|
766
903
|
});
|
|
767
904
|
if (clack.isCancel(shouldInstall)) {
|
|
905
|
+
clack.cancel("Operation cancelled.");
|
|
906
|
+
process.exit(0);
|
|
768
907
|
}
|
|
769
908
|
if (shouldInstall) {
|
|
770
909
|
try {
|