create-vxrn 0.1.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/LICENSE +21 -0
- package/biome.json +78 -0
- package/dist/helpers/cloneStarter.js +79 -0
- package/dist/helpers/cloneStarter.js.map +6 -0
- package/dist/helpers/cloneStarter.native.js +320 -0
- package/dist/helpers/cloneStarter.native.js.map +6 -0
- package/dist/helpers/getProjectName.js +45 -0
- package/dist/helpers/getProjectName.js.map +6 -0
- package/dist/helpers/getProjectName.native.js +185 -0
- package/dist/helpers/getProjectName.native.js.map +6 -0
- package/dist/helpers/getTemplateInfo.js +38 -0
- package/dist/helpers/getTemplateInfo.js.map +6 -0
- package/dist/helpers/getTemplateInfo.native.js +191 -0
- package/dist/helpers/getTemplateInfo.native.js.map +6 -0
- package/dist/helpers/installDependencies.js +33 -0
- package/dist/helpers/installDependencies.js.map +6 -0
- package/dist/helpers/installDependencies.native.js +187 -0
- package/dist/helpers/installDependencies.native.js.map +6 -0
- package/dist/helpers/validateNpmPackage.js +36 -0
- package/dist/helpers/validateNpmPackage.js.map +6 -0
- package/dist/helpers/validateNpmPackage.native.js +74 -0
- package/dist/helpers/validateNpmPackage.native.js.map +6 -0
- package/dist/index.js +114 -0
- package/dist/index.js.map +6 -0
- package/dist/index.native.js +300 -0
- package/dist/index.native.js.map +6 -0
- package/dist/steps/bare.js +38 -0
- package/dist/steps/bare.js.map +6 -0
- package/dist/steps/bare.native.js +163 -0
- package/dist/steps/bare.native.js.map +6 -0
- package/dist/steps/expo-router.js +41 -0
- package/dist/steps/expo-router.js.map +6 -0
- package/dist/steps/expo-router.native.js +168 -0
- package/dist/steps/expo-router.native.js.map +6 -0
- package/dist/steps/tamagui.js +41 -0
- package/dist/steps/tamagui.js.map +6 -0
- package/dist/steps/tamagui.native.js +168 -0
- package/dist/steps/tamagui.native.js.map +6 -0
- package/dist/steps/types.js +14 -0
- package/dist/steps/types.js.map +6 -0
- package/dist/steps/types.native.js +15 -0
- package/dist/steps/types.native.js.map +6 -0
- package/dist/templates.js +84 -0
- package/dist/templates.js.map +6 -0
- package/dist/templates.native.js +97 -0
- package/dist/templates.native.js.map +6 -0
- package/package.json +33 -0
- package/readme.md +5 -0
- package/run.js +12 -0
- package/src/helpers/cloneStarter.ts +115 -0
- package/src/helpers/getProjectName.ts +46 -0
- package/src/helpers/getTemplateInfo.ts +32 -0
- package/src/helpers/installDependencies.ts +14 -0
- package/src/helpers/validateNpmPackage.ts +16 -0
- package/src/index.ts +170 -0
- package/src/steps/bare.ts +21 -0
- package/src/steps/expo-router.ts +25 -0
- package/src/steps/tamagui.ts +25 -0
- package/src/steps/types.ts +5 -0
- package/src/templates.ts +62 -0
- package/tsconfig.json +12 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf, __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: !0 });
|
|
9
|
+
}, __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from == "object" || typeof from == "function")
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
!__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
return to;
|
|
14
|
+
};
|
|
15
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
16
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
17
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
18
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
19
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
20
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: !0 }) : target,
|
|
21
|
+
mod
|
|
22
|
+
)), __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: !0 }), mod);
|
|
23
|
+
var templates_exports = {};
|
|
24
|
+
__export(templates_exports, {
|
|
25
|
+
templates: () => templates
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(templates_exports);
|
|
28
|
+
var import_bare = __toESM(require("./steps/bare")), import_expo_router = __toESM(require("./steps/expo-router")), import_tamagui = __toESM(require("./steps/tamagui"));
|
|
29
|
+
const templates = [
|
|
30
|
+
// {
|
|
31
|
+
// title: `Free - Expo + Next in a production ready monorepo`,
|
|
32
|
+
// value: 'starter-free',
|
|
33
|
+
// type: 'free',
|
|
34
|
+
// hidden: false,
|
|
35
|
+
// packageManager: 'yarn',
|
|
36
|
+
// repo: {
|
|
37
|
+
// url: `https://github.com/tamagui/starter-free.git`,
|
|
38
|
+
// sshFallback: `git@github.com:tamagui/starter-free.git`,
|
|
39
|
+
// dir: [],
|
|
40
|
+
// branch: 'main',
|
|
41
|
+
// },
|
|
42
|
+
// extraSteps: starterFree,
|
|
43
|
+
// },
|
|
44
|
+
{
|
|
45
|
+
title: "Bare",
|
|
46
|
+
value: "bare",
|
|
47
|
+
type: "included-in-monorepo",
|
|
48
|
+
hidden: !1,
|
|
49
|
+
repo: {
|
|
50
|
+
url: "https://github.com/natew/vxrn.git",
|
|
51
|
+
sshFallback: "git@github.com:natew/vxrn.git",
|
|
52
|
+
dir: ["examples", "vxrn"],
|
|
53
|
+
branch: "main"
|
|
54
|
+
},
|
|
55
|
+
extraSteps: import_bare.default
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
title: "Tamagui",
|
|
59
|
+
value: "tamagui",
|
|
60
|
+
type: "included-in-monorepo",
|
|
61
|
+
hidden: !1,
|
|
62
|
+
repo: {
|
|
63
|
+
url: "https://github.com/natew/vxrn.git",
|
|
64
|
+
sshFallback: "git@github.com:natew/vxrn.git",
|
|
65
|
+
dir: ["examples", "tamagui"],
|
|
66
|
+
branch: "main"
|
|
67
|
+
},
|
|
68
|
+
extraSteps: import_tamagui.default
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
title: "Expo Router",
|
|
72
|
+
value: "expo-router",
|
|
73
|
+
type: "included-in-monorepo",
|
|
74
|
+
hidden: !1,
|
|
75
|
+
repo: {
|
|
76
|
+
url: "https://github.com/natew/vxrn.git",
|
|
77
|
+
sshFallback: "git@github.com:natew/vxrn.git",
|
|
78
|
+
dir: ["examples", "expo-router"],
|
|
79
|
+
branch: "main"
|
|
80
|
+
},
|
|
81
|
+
extraSteps: import_expo_router.default
|
|
82
|
+
}
|
|
83
|
+
];
|
|
84
|
+
//# sourceMappingURL=templates.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/templates.ts"],
|
|
4
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAsB,kCACtB,qBAA4B,yCAC5B,iBAAyB;AAElB,MAAM,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBvB;AAAA,IACE,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,MAAM;AAAA,MACJ,KAAK;AAAA,MACL,aAAa;AAAA,MACb,KAAK,CAAC,YAAY,MAAM;AAAA,MACxB,QAAQ;AAAA,IACV;AAAA,IACA,YAAY,YAAAA;AAAA,EACd;AAAA,EAEA;AAAA,IACE,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,MAAM;AAAA,MACJ,KAAK;AAAA,MACL,aAAa;AAAA,MACb,KAAK,CAAC,YAAY,SAAS;AAAA,MAC3B,QAAQ;AAAA,IACV;AAAA,IACA,YAAY,eAAAC;AAAA,EACd;AAAA,EAEA;AAAA,IACE,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,MAAM;AAAA,MACJ,KAAK;AAAA,MACL,aAAa;AAAA,MACb,KAAK,CAAC,YAAY,aAAa;AAAA,MAC/B,QAAQ;AAAA,IACV;AAAA,IACA,YAAY,mBAAAC;AAAA,EACd;AACF;",
|
|
5
|
+
"names": ["stepsBare", "stepsTamagui", "stepsExpoRouter"]
|
|
6
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf, __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: !0 });
|
|
10
|
+
}, __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from == "object" || typeof from == "function")
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
!__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: !0 }) : target,
|
|
22
|
+
mod
|
|
23
|
+
)), __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: !0 }), mod);
|
|
24
|
+
var templates_exports = {};
|
|
25
|
+
__export(templates_exports, {
|
|
26
|
+
templates: () => templates
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(templates_exports);
|
|
29
|
+
var import_bare = __toESM(require("./steps/bare")), import_expo_router = __toESM(require("./steps/expo-router")), import_tamagui = __toESM(require("./steps/tamagui")), templates = [
|
|
30
|
+
// {
|
|
31
|
+
// title: `Free - Expo + Next in a production ready monorepo`,
|
|
32
|
+
// value: 'starter-free',
|
|
33
|
+
// type: 'free',
|
|
34
|
+
// hidden: false,
|
|
35
|
+
// packageManager: 'yarn',
|
|
36
|
+
// repo: {
|
|
37
|
+
// url: `https://github.com/tamagui/starter-free.git`,
|
|
38
|
+
// sshFallback: `git@github.com:tamagui/starter-free.git`,
|
|
39
|
+
// dir: [],
|
|
40
|
+
// branch: 'main',
|
|
41
|
+
// },
|
|
42
|
+
// extraSteps: starterFree,
|
|
43
|
+
// },
|
|
44
|
+
{
|
|
45
|
+
title: "Bare",
|
|
46
|
+
value: "bare",
|
|
47
|
+
type: "included-in-monorepo",
|
|
48
|
+
hidden: !1,
|
|
49
|
+
repo: {
|
|
50
|
+
url: "https://github.com/natew/vxrn.git",
|
|
51
|
+
sshFallback: "git@github.com:natew/vxrn.git",
|
|
52
|
+
dir: [
|
|
53
|
+
"examples",
|
|
54
|
+
"vxrn"
|
|
55
|
+
],
|
|
56
|
+
branch: "main"
|
|
57
|
+
},
|
|
58
|
+
extraSteps: import_bare.default
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
title: "Tamagui",
|
|
62
|
+
value: "tamagui",
|
|
63
|
+
type: "included-in-monorepo",
|
|
64
|
+
hidden: !1,
|
|
65
|
+
repo: {
|
|
66
|
+
url: "https://github.com/natew/vxrn.git",
|
|
67
|
+
sshFallback: "git@github.com:natew/vxrn.git",
|
|
68
|
+
dir: [
|
|
69
|
+
"examples",
|
|
70
|
+
"tamagui"
|
|
71
|
+
],
|
|
72
|
+
branch: "main"
|
|
73
|
+
},
|
|
74
|
+
extraSteps: import_tamagui.default
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
title: "Expo Router",
|
|
78
|
+
value: "expo-router",
|
|
79
|
+
type: "included-in-monorepo",
|
|
80
|
+
hidden: !1,
|
|
81
|
+
repo: {
|
|
82
|
+
url: "https://github.com/natew/vxrn.git",
|
|
83
|
+
sshFallback: "git@github.com:natew/vxrn.git",
|
|
84
|
+
dir: [
|
|
85
|
+
"examples",
|
|
86
|
+
"expo-router"
|
|
87
|
+
],
|
|
88
|
+
branch: "main"
|
|
89
|
+
},
|
|
90
|
+
extraSteps: import_expo_router.default
|
|
91
|
+
}
|
|
92
|
+
];
|
|
93
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
94
|
+
0 && (module.exports = {
|
|
95
|
+
templates
|
|
96
|
+
});
|
|
97
|
+
//# sourceMappingURL=templates.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/Users/n8/vxrn/packages/create-vxrn/src/templates.ts"],
|
|
4
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;kBAAsB,kCACtB,qBAA4B,yCAC5B,iBAAyB,qCAEZA,YAAY;;;;;;;;;;;;;;;EAgBvB;IACEC,OAAQ;IACRC,OAAO;IACPC,MAAM;IACNC,QAAQ;IACRC,MAAM;MACJC,KAAM;MACNC,aAAc;MACdC,KAAK;QAAE;QAAY;;MACnBC,QAAQ;IACV;IACAC,YAAYC,YAAAA;EACd;EAEA;IACEV,OAAQ;IACRC,OAAO;IACPC,MAAM;IACNC,QAAQ;IACRC,MAAM;MACJC,KAAM;MACNC,aAAc;MACdC,KAAK;QAAE;QAAY;;MACnBC,QAAQ;IACV;IACAC,YAAYE,eAAAA;EACd;EAEA;IACEX,OAAQ;IACRC,OAAO;IACPC,MAAM;IACNC,QAAQ;IACRC,MAAM;MACJC,KAAM;MACNC,aAAc;MACdC,KAAK;QAAE;QAAY;;MACnBC,QAAQ;IACV;IACAC,YAAYG,mBAAAA;EACd;;",
|
|
5
|
+
"names": ["templates", "title", "value", "type", "hidden", "repo", "url", "sshFallback", "dir", "branch", "extraSteps", "stepsBare", "stepsTamagui", "stepsExpoRouter"]
|
|
6
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-vxrn",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"bin": "./run.js",
|
|
5
|
+
"main": "dist",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "./run.js",
|
|
8
|
+
"prerelease": "rimraf ./dist/",
|
|
9
|
+
"prepublish": "yarn build",
|
|
10
|
+
"build": "tamagui-build --skip-types",
|
|
11
|
+
"watch": "yarn build --watch",
|
|
12
|
+
"clean": "tamagui-build clean",
|
|
13
|
+
"clean:build": "tamagui-build clean:build"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@expo/package-manager": "^1.1.2",
|
|
17
|
+
"@tamagui/build": "^1.94.4",
|
|
18
|
+
"@types/prompts": "^2.4.9",
|
|
19
|
+
"@types/validate-npm-package-name": "^4.0.2",
|
|
20
|
+
"ansis": "^3.1.0",
|
|
21
|
+
"async-retry": "1.3.1",
|
|
22
|
+
"citty": "^0.1.6",
|
|
23
|
+
"cpy": "^11.0.1",
|
|
24
|
+
"detect-package-manager": "^3.0.1",
|
|
25
|
+
"fs-extra": "^11.2.0",
|
|
26
|
+
"prompts": "2.1.0",
|
|
27
|
+
"rimraf": "^5.0.1",
|
|
28
|
+
"validate-npm-package-name": "3.0.0"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
}
|
|
33
|
+
}
|
package/readme.md
ADDED
package/run.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const command = require.resolve('create-vxrn')
|
|
4
|
+
const args = process.argv.slice(2)
|
|
5
|
+
|
|
6
|
+
try {
|
|
7
|
+
require('node:child_process').execSync(`node ${command} ${args.join(' ')}`, {
|
|
8
|
+
stdio: 'inherit',
|
|
9
|
+
})
|
|
10
|
+
} catch (err) {
|
|
11
|
+
process.exit(1)
|
|
12
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process'
|
|
2
|
+
import { homedir } from 'node:os'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
|
|
5
|
+
import ansis from 'ansis'
|
|
6
|
+
import { copy, ensureDir, pathExists, remove } from 'fs-extra'
|
|
7
|
+
import { rimraf } from 'rimraf'
|
|
8
|
+
|
|
9
|
+
import type { templates } from '../templates'
|
|
10
|
+
|
|
11
|
+
const exec = (cmd: string, options?: Parameters<typeof execSync>[1]) => {
|
|
12
|
+
return execSync(cmd, {
|
|
13
|
+
stdio: process.env.DEBUG ? 'inherit' : 'ignore',
|
|
14
|
+
...options,
|
|
15
|
+
})
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const home = homedir()
|
|
19
|
+
const vxrnDir = join(home, '.vxrn')
|
|
20
|
+
let targetGitDir = ''
|
|
21
|
+
|
|
22
|
+
export const cloneStarter = async (
|
|
23
|
+
template: (typeof templates)[number],
|
|
24
|
+
resolvedProjectPath: string,
|
|
25
|
+
projectName: string
|
|
26
|
+
) => {
|
|
27
|
+
targetGitDir = join(vxrnDir, 'vxrn', template.repo.url.split('/').at(-1)!)
|
|
28
|
+
|
|
29
|
+
console.info()
|
|
30
|
+
await setupVxrnDotDir(template)
|
|
31
|
+
const starterDir = join(targetGitDir, ...template.repo.dir)
|
|
32
|
+
console.info()
|
|
33
|
+
console.info(`Copying starter from ${starterDir} into ${ansis.blueBright(projectName)}...`)
|
|
34
|
+
console.info()
|
|
35
|
+
|
|
36
|
+
// if (!(await pathExists(starterDir))) {
|
|
37
|
+
// console.error(`Missing template for ${template.value} in ${starterDir}`)
|
|
38
|
+
// process.exit(1)
|
|
39
|
+
// }
|
|
40
|
+
await copy(starterDir, resolvedProjectPath)
|
|
41
|
+
await rimraf(`${resolvedProjectPath}/.git`)
|
|
42
|
+
|
|
43
|
+
console.info(ansis.green(`${projectName} created!`))
|
|
44
|
+
console.info()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function setupVxrnDotDir(template: (typeof templates)[number], isRetry = false) {
|
|
48
|
+
const repoRoot = join(__dirname, '..', '..', '..')
|
|
49
|
+
|
|
50
|
+
console.info(`Setting up ${ansis.blueBright(targetGitDir)}...`)
|
|
51
|
+
|
|
52
|
+
const branch = template.repo.branch
|
|
53
|
+
|
|
54
|
+
await ensureDir(vxrnDir)
|
|
55
|
+
|
|
56
|
+
const isInSubDir = template.repo.dir.length > 0
|
|
57
|
+
|
|
58
|
+
if (!(await pathExists(targetGitDir))) {
|
|
59
|
+
console.info(`Cloning vxrn base directory`)
|
|
60
|
+
console.info()
|
|
61
|
+
|
|
62
|
+
const sourceGitRepo = template.repo.url
|
|
63
|
+
const sourceGitRepoSshFallback = template.repo.sshFallback
|
|
64
|
+
|
|
65
|
+
const cmd = `git clone --branch ${branch} ${
|
|
66
|
+
isInSubDir ? '--depth 1 --sparse --filter=blob:none ' : ''
|
|
67
|
+
}${sourceGitRepo} "${targetGitDir}"`
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
console.info(`$ ${cmd}`)
|
|
71
|
+
console.info()
|
|
72
|
+
exec(cmd)
|
|
73
|
+
} catch (error) {
|
|
74
|
+
if (cmd.includes('https://')) {
|
|
75
|
+
console.info(`https failed - trying with ssh now...`)
|
|
76
|
+
const sshCmd = cmd.replace(sourceGitRepo, sourceGitRepoSshFallback)
|
|
77
|
+
console.info(`$ ${sshCmd}`)
|
|
78
|
+
console.info()
|
|
79
|
+
exec(sshCmd)
|
|
80
|
+
} else {
|
|
81
|
+
throw error
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
if (!(await pathExists(join(targetGitDir, '.git')))) {
|
|
86
|
+
console.error(`Corrupt Vxrn directory, please delete ${targetGitDir} and re-run`)
|
|
87
|
+
process.exit(1)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (isInSubDir) {
|
|
92
|
+
const cmd = `git sparse-checkout set ${template.repo.dir[0] ?? '.'}`
|
|
93
|
+
exec(cmd, { cwd: targetGitDir })
|
|
94
|
+
console.info()
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
const cmd2 = `git pull --rebase --allow-unrelated-histories --depth 1 origin ${branch}`
|
|
98
|
+
exec(cmd2, {
|
|
99
|
+
cwd: targetGitDir,
|
|
100
|
+
})
|
|
101
|
+
console.info()
|
|
102
|
+
} catch (err: any) {
|
|
103
|
+
console.info(
|
|
104
|
+
`Error updating: ${err.message} ${isRetry ? `failing.\n${err.stack}` : 'trying from fresh.'}`
|
|
105
|
+
)
|
|
106
|
+
if (isRetry) {
|
|
107
|
+
console.info(
|
|
108
|
+
`Please file an issue: https://github.com/vxrn/vxrn/issues/new?assignees=&labels=&template=bug_report.md&title=`
|
|
109
|
+
)
|
|
110
|
+
process.exit(1)
|
|
111
|
+
}
|
|
112
|
+
await remove(targetGitDir)
|
|
113
|
+
await setupVxrnDotDir(template, true)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
|
|
3
|
+
import ansis from 'ansis'
|
|
4
|
+
import prompts from 'prompts'
|
|
5
|
+
|
|
6
|
+
import packageJson from '../../package.json'
|
|
7
|
+
import { validateNpmName } from './validateNpmPackage'
|
|
8
|
+
|
|
9
|
+
export const getProjectName = async (projectPath?: string) => {
|
|
10
|
+
if (typeof projectPath === 'string') {
|
|
11
|
+
projectPath = projectPath.trim()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (!projectPath) {
|
|
15
|
+
const res = await prompts({
|
|
16
|
+
type: 'text',
|
|
17
|
+
name: 'path',
|
|
18
|
+
message: 'Project name:',
|
|
19
|
+
initial: 'myapp',
|
|
20
|
+
validate: (name) => {
|
|
21
|
+
const validation = validateNpmName(path.basename(path.resolve(name)))
|
|
22
|
+
if (validation.valid) {
|
|
23
|
+
return true
|
|
24
|
+
}
|
|
25
|
+
return 'Invalid project name: ' + validation.problems![0]
|
|
26
|
+
},
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
if (typeof res.path === 'string') {
|
|
30
|
+
projectPath = res.path.trim()
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!projectPath) {
|
|
35
|
+
console.info()
|
|
36
|
+
console.info('Please specify the project directory:')
|
|
37
|
+
console.info(` ${ansis.cyan(packageJson.name)} ${ansis.green('<project-directory>')}`)
|
|
38
|
+
console.info()
|
|
39
|
+
console.info('For example:')
|
|
40
|
+
console.info(` ${ansis.cyan(packageJson.name)} ${ansis.green('my-app')}`)
|
|
41
|
+
console.info()
|
|
42
|
+
console.info(`Run ${ansis.cyan(`${packageJson.name} --help`)} to see all options.`)
|
|
43
|
+
process.exit(1)
|
|
44
|
+
}
|
|
45
|
+
return projectPath
|
|
46
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import prompts from 'prompts'
|
|
2
|
+
|
|
3
|
+
import { templates } from '../templates'
|
|
4
|
+
|
|
5
|
+
const validTemplates = templates.map(({ value }) => value).join(', ')
|
|
6
|
+
|
|
7
|
+
export const getTemplateInfo = async (template?: string): Promise<(typeof templates)[number]> => {
|
|
8
|
+
let res = getValidTemplate(template)
|
|
9
|
+
if (template && !res) {
|
|
10
|
+
console.warn(`template ${template} is not valid. valid options: ${validTemplates}`)
|
|
11
|
+
process.exit(1)
|
|
12
|
+
}
|
|
13
|
+
if (!res) {
|
|
14
|
+
template = (
|
|
15
|
+
await prompts({
|
|
16
|
+
name: 'template',
|
|
17
|
+
type: 'select',
|
|
18
|
+
message: `Pick a template:`,
|
|
19
|
+
choices: templates.filter((t) => !t.hidden),
|
|
20
|
+
})
|
|
21
|
+
).template
|
|
22
|
+
}
|
|
23
|
+
res = getValidTemplate(`${template}`)
|
|
24
|
+
if (!res) {
|
|
25
|
+
console.warn(`template ${template} is not valid. valid options: ${validTemplates}`)
|
|
26
|
+
process.exit(1)
|
|
27
|
+
}
|
|
28
|
+
return res
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const getValidTemplate = (template?: string) =>
|
|
32
|
+
typeof template === 'string' && templates.find(({ value }) => value === template)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as PackageManager from '@expo/package-manager'
|
|
2
|
+
|
|
3
|
+
export async function installDependencies(
|
|
4
|
+
projectRoot: string,
|
|
5
|
+
packageManager: 'yarn' | 'npm' | 'pnpm' | 'bun'
|
|
6
|
+
) {
|
|
7
|
+
const options = { cwd: projectRoot }
|
|
8
|
+
if (packageManager === 'yarn') {
|
|
9
|
+
const yarn = new PackageManager.YarnPackageManager(options)
|
|
10
|
+
await yarn.installAsync()
|
|
11
|
+
} else {
|
|
12
|
+
await new PackageManager.NpmPackageManager(options).installAsync()
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import validateProjectName from 'validate-npm-package-name'
|
|
2
|
+
|
|
3
|
+
export function validateNpmName(name: string): {
|
|
4
|
+
valid: boolean
|
|
5
|
+
problems?: string[]
|
|
6
|
+
} {
|
|
7
|
+
const nameValidation = validateProjectName(name)
|
|
8
|
+
if (nameValidation.validForNewPackages) {
|
|
9
|
+
return { valid: true }
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
valid: false,
|
|
14
|
+
problems: [...(nameValidation.errors || []), ...(nameValidation.warnings || [])],
|
|
15
|
+
}
|
|
16
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// inspired by https://github.com/vercel/next.js/blob/0355e5f63f87db489f36db8d814958cb4c2b828b/packages/create-next-app/helpers/examples.ts#L71
|
|
3
|
+
|
|
4
|
+
import ansis from 'ansis'
|
|
5
|
+
import { defineCommand, runMain } from 'citty'
|
|
6
|
+
import { detect } from 'detect-package-manager'
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync } from 'fs-extra'
|
|
8
|
+
import { execSync } from 'node:child_process'
|
|
9
|
+
import fs from 'node:fs'
|
|
10
|
+
import path from 'node:path'
|
|
11
|
+
import { cwd } from 'node:process'
|
|
12
|
+
import packageJson from '../package.json'
|
|
13
|
+
import { cloneStarter } from './helpers/cloneStarter'
|
|
14
|
+
import { getProjectName } from './helpers/getProjectName'
|
|
15
|
+
import { getTemplateInfo } from './helpers/getTemplateInfo'
|
|
16
|
+
import { installDependencies } from './helpers/installDependencies'
|
|
17
|
+
import { validateNpmName } from './helpers/validateNpmPackage'
|
|
18
|
+
|
|
19
|
+
let projectPath = ''
|
|
20
|
+
|
|
21
|
+
function exit() {
|
|
22
|
+
process.exit(0)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
process.on('SIGTERM', exit)
|
|
26
|
+
process.on('SIGINT', exit)
|
|
27
|
+
|
|
28
|
+
const main = defineCommand({
|
|
29
|
+
meta: {
|
|
30
|
+
name: 'main',
|
|
31
|
+
version: '0.0.0',
|
|
32
|
+
description: 'Welcome to vxrn',
|
|
33
|
+
},
|
|
34
|
+
args: {
|
|
35
|
+
directory: {
|
|
36
|
+
type: 'positional',
|
|
37
|
+
description: 'Directory to copy into',
|
|
38
|
+
default: '',
|
|
39
|
+
},
|
|
40
|
+
template: {
|
|
41
|
+
type: 'string',
|
|
42
|
+
default: 'bare',
|
|
43
|
+
description: 'One of "bare", "tamagui", "expo-router".',
|
|
44
|
+
},
|
|
45
|
+
info: {
|
|
46
|
+
type: 'boolean',
|
|
47
|
+
description: 'Output the post-install instructions for the template.',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
async run({ args }) {
|
|
51
|
+
if (args.info) {
|
|
52
|
+
let template = await getTemplateInfo(args.template)
|
|
53
|
+
await template.extraSteps({
|
|
54
|
+
isFullClone: false,
|
|
55
|
+
projectName: path.basename(cwd()),
|
|
56
|
+
projectPath: cwd(),
|
|
57
|
+
})
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
console.info()
|
|
62
|
+
console.info(
|
|
63
|
+
ansis.bold(' Note: You may need to run "npm create vxrn@latest" to get the latest version!')
|
|
64
|
+
)
|
|
65
|
+
console.info()
|
|
66
|
+
|
|
67
|
+
console.info() // this newline prevents the ascii art from breaking
|
|
68
|
+
console.info(ansis.bold('Creating vxrn app...'))
|
|
69
|
+
|
|
70
|
+
const gitVersionString = Number.parseFloat(
|
|
71
|
+
execSync(`git --version`).toString().replace(`git version `, '').trim()
|
|
72
|
+
)
|
|
73
|
+
if (gitVersionString < 2.27) {
|
|
74
|
+
console.error(`\n\n ⚠️ vxrn can't install: Git version must be >= 2.27\n\n`)
|
|
75
|
+
process.exit(1)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
projectPath ||= await getProjectName(projectPath)
|
|
79
|
+
|
|
80
|
+
let template = await getTemplateInfo(args.template)
|
|
81
|
+
|
|
82
|
+
// space
|
|
83
|
+
console.info()
|
|
84
|
+
|
|
85
|
+
const resolvedProjectPath = path.resolve(process.cwd(), projectPath)
|
|
86
|
+
const projectName = path.basename(resolvedProjectPath)
|
|
87
|
+
|
|
88
|
+
const { valid, problems } = validateNpmName(projectName)
|
|
89
|
+
if (!valid) {
|
|
90
|
+
console.error(
|
|
91
|
+
`Could not create a project called ${ansis.red(
|
|
92
|
+
`"${projectName}"`
|
|
93
|
+
)} because of npm naming restrictions:`
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
problems!.forEach((p) => console.error(` ${ansis.red.bold('*')} ${p}`))
|
|
97
|
+
process.exit(1)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (fs.existsSync(resolvedProjectPath)) {
|
|
101
|
+
console.info()
|
|
102
|
+
console.info(
|
|
103
|
+
ansis.red('🚨 [vxrn] error'),
|
|
104
|
+
`You tried to make a project called ${ansis.underline(
|
|
105
|
+
ansis.blueBright(projectName)
|
|
106
|
+
)}, but a folder with that name already exists: ${ansis.blueBright(resolvedProjectPath)}
|
|
107
|
+
|
|
108
|
+
${ansis.bold(ansis.red(`Please pick a different project name 🥸`))}`
|
|
109
|
+
)
|
|
110
|
+
console.info()
|
|
111
|
+
console.info()
|
|
112
|
+
process.exit(1)
|
|
113
|
+
}
|
|
114
|
+
console.info()
|
|
115
|
+
console.info(`Creating a new vxrn app ${ansis.blueBright(resolvedProjectPath)}...`)
|
|
116
|
+
fs.mkdirSync(resolvedProjectPath)
|
|
117
|
+
console.info(ansis.green(`${projectName} folder created.`))
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
await cloneStarter(template, resolvedProjectPath, projectName)
|
|
121
|
+
process.chdir(resolvedProjectPath)
|
|
122
|
+
// space
|
|
123
|
+
console.info()
|
|
124
|
+
} catch (e) {
|
|
125
|
+
console.error(`[vxrn] Failed to copy example into ${resolvedProjectPath}\n\n`, e)
|
|
126
|
+
process.exit(1)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// change root package.json's name to project name
|
|
130
|
+
updatePackageJsonName(projectName, resolvedProjectPath)
|
|
131
|
+
|
|
132
|
+
console.info('Installing packages. This might take a couple of minutes.')
|
|
133
|
+
console.info()
|
|
134
|
+
|
|
135
|
+
const packageManager =
|
|
136
|
+
('packageManager' in template ? template.packageManager : undefined) || (await detect())
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
console.info('installing with ' + packageManager)
|
|
140
|
+
await installDependencies(resolvedProjectPath, packageManager as any)
|
|
141
|
+
} catch (e: any) {
|
|
142
|
+
console.error('[vxrn] error installing with ' + packageManager + '\n' + `${e}`)
|
|
143
|
+
process.exit(1)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
await template.extraSteps({
|
|
147
|
+
isFullClone: true,
|
|
148
|
+
projectName,
|
|
149
|
+
projectPath: resolvedProjectPath,
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
console.info()
|
|
153
|
+
},
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
runMain(main)
|
|
157
|
+
|
|
158
|
+
if (process.argv.includes('--version')) {
|
|
159
|
+
console.info(packageJson.version)
|
|
160
|
+
process.exit(0)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function updatePackageJsonName(projectName: string, dir: string) {
|
|
164
|
+
const packageJsonPath = path.join(dir, 'package.json')
|
|
165
|
+
if (existsSync(packageJsonPath)) {
|
|
166
|
+
const content = readFileSync(packageJsonPath).toString()
|
|
167
|
+
const contentWithUpdatedName = content.replace(/("name": ")(.*)(",)/, `$1${projectName}$3`)
|
|
168
|
+
writeFileSync(packageJsonPath, contentWithUpdatedName)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import ansis from 'ansis'
|
|
2
|
+
|
|
3
|
+
import type { ExtraSteps } from './types'
|
|
4
|
+
|
|
5
|
+
const packageManager = 'yarn'
|
|
6
|
+
const useYarn = packageManager === 'yarn'
|
|
7
|
+
|
|
8
|
+
const runCommand = (scriptName: string) => `${packageManager} ${useYarn ? '' : 'run '}${scriptName}`
|
|
9
|
+
|
|
10
|
+
const main: ExtraSteps = async ({ isFullClone, projectName }) => {
|
|
11
|
+
if (isFullClone) {
|
|
12
|
+
console.info(`
|
|
13
|
+
${ansis.green.bold('Done!')} created a new project under ./${projectName}
|
|
14
|
+
|
|
15
|
+
visit your project:
|
|
16
|
+
${ansis.green('cd')} ${projectName}
|
|
17
|
+
`)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default main
|