create-tina-app 0.0.0-d7c5ec1-20250219020924 → 0.0.0-d813ac1-20251210222143
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/README.md +1 -1
- package/bin/create-tina-app +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +526 -265
- package/dist/templates.d.ts +9 -2
- package/dist/themes.d.ts +7 -0
- package/dist/util/asciiArt.d.ts +3 -0
- package/dist/util/checkPkgManagers.d.ts +2 -2
- package/dist/util/fileUtil.d.ts +1 -0
- package/dist/util/git.d.ts +2 -1
- package/dist/util/install.d.ts +3 -17
- package/dist/util/isNpm.d.ts +16 -0
- package/dist/util/options.d.ts +9 -0
- package/dist/util/packageManagers.d.ts +7 -0
- package/dist/util/preRunChecks.d.ts +2 -1
- package/dist/util/textstyles.d.ts +10 -0
- package/package.json +6 -5
- package/dist/util/logger.d.ts +0 -20
package/README.md
CHANGED
|
@@ -6,6 +6,6 @@ Create Tina App is a powerful command-line interface (CLI) tool designed to kick
|
|
|
6
6
|
|
|
7
7
|
To get started, you need to first build the code - see [contributing](https://github.com/tinacms/tinacms/blob/main/CONTRIBUTING.md).
|
|
8
8
|
|
|
9
|
-
1. run `pnpm link
|
|
9
|
+
1. run `pnpm link --global`
|
|
10
10
|
1. Test your changes by running `npx create-tina-app`
|
|
11
11
|
1. Run `pnpm unlink` when done to unlink the local build
|
package/bin/create-tina-app
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,91 +1,30 @@
|
|
|
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;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __export = (target, all) => {
|
|
8
|
-
for (var name2 in all)
|
|
9
|
-
__defProp(target, name2, { get: all[name2], enumerable: true });
|
|
10
|
-
};
|
|
11
|
-
var __copyProps = (to, from, except, desc) => {
|
|
12
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
-
for (let key of __getOwnPropNames(from))
|
|
14
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
-
}
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
-
mod
|
|
26
|
-
));
|
|
27
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
-
|
|
29
1
|
// src/index.ts
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
});
|
|
35
|
-
module.exports = __toCommonJS(index_exports);
|
|
36
|
-
var import_metrics = require("@tinacms/metrics");
|
|
37
|
-
var import_commander = require("commander");
|
|
38
|
-
var import_prompts = __toESM(require("prompts"));
|
|
39
|
-
var import_node_path = __toESM(require("path"));
|
|
40
|
-
|
|
41
|
-
// package.json
|
|
42
|
-
var name = "create-tina-app";
|
|
43
|
-
var version = "1.3.1";
|
|
2
|
+
import { Telemetry } from "@tinacms/metrics";
|
|
3
|
+
import prompts from "prompts";
|
|
4
|
+
import path4 from "node:path";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
44
6
|
|
|
45
7
|
// src/util/fileUtil.ts
|
|
46
|
-
|
|
47
|
-
|
|
8
|
+
import fs from "fs-extra";
|
|
9
|
+
import path from "path";
|
|
48
10
|
|
|
49
|
-
// src/util/
|
|
50
|
-
|
|
11
|
+
// src/util/textstyles.ts
|
|
12
|
+
import chalk from "chalk";
|
|
51
13
|
var TextStyles = {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
var Logger = class {
|
|
61
|
-
log(message) {
|
|
62
|
-
console.info(message);
|
|
63
|
-
}
|
|
64
|
-
debug(message) {
|
|
65
|
-
console.debug(TextStyles.info(`[DEBUG] ${message}`));
|
|
66
|
-
}
|
|
67
|
-
info(message) {
|
|
68
|
-
console.info(TextStyles.info(`[INFO] ${message}`));
|
|
69
|
-
}
|
|
70
|
-
success(message) {
|
|
71
|
-
console.log(TextStyles.success(`[SUCCESS] ${message}`));
|
|
72
|
-
}
|
|
73
|
-
cmd(message) {
|
|
74
|
-
console.log(TextStyles.cmd(message));
|
|
75
|
-
}
|
|
76
|
-
warn(message) {
|
|
77
|
-
console.warn(TextStyles.warn(`[WARNING] ${message}`));
|
|
78
|
-
}
|
|
79
|
-
err(message) {
|
|
80
|
-
console.error(TextStyles.err(`[ERROR] ${message}`));
|
|
81
|
-
}
|
|
14
|
+
tinaOrange: chalk.hex("#EC4816"),
|
|
15
|
+
link: (url) => `\x1B]8;;${url}\x07${chalk.cyan.underline(url)}\x1B]8;;\x07`,
|
|
16
|
+
cmd: chalk.bgBlackBright.bold.white,
|
|
17
|
+
info: chalk.blue,
|
|
18
|
+
success: chalk.green,
|
|
19
|
+
warn: chalk.yellow,
|
|
20
|
+
err: chalk.red,
|
|
21
|
+
bold: chalk.bold
|
|
82
22
|
};
|
|
83
|
-
var log = new Logger();
|
|
84
23
|
|
|
85
24
|
// src/util/fileUtil.ts
|
|
86
25
|
async function isWriteable(directory) {
|
|
87
26
|
try {
|
|
88
|
-
await
|
|
27
|
+
await fs.promises.access(directory, (fs.constants || fs).W_OK);
|
|
89
28
|
return true;
|
|
90
29
|
} catch (err) {
|
|
91
30
|
return false;
|
|
@@ -112,108 +51,71 @@ function folderContainsInstallConflicts(root) {
|
|
|
112
51
|
"yarn-debug.log",
|
|
113
52
|
"yarn-error.log"
|
|
114
53
|
];
|
|
115
|
-
const conflicts =
|
|
54
|
+
const conflicts = fs.readdirSync(root).filter((file) => !validFiles.includes(file)).filter((file) => !/\.iml$/.test(file));
|
|
116
55
|
return conflicts;
|
|
117
56
|
}
|
|
118
57
|
async function setupProjectDirectory(dir) {
|
|
119
|
-
const appName =
|
|
120
|
-
await
|
|
58
|
+
const appName = path.basename(dir);
|
|
59
|
+
await fs.mkdirp(dir);
|
|
121
60
|
process.chdir(dir);
|
|
122
61
|
const conflicts = folderContainsInstallConflicts(dir);
|
|
123
62
|
if (conflicts.length > 0) {
|
|
124
|
-
|
|
125
|
-
`The directory '${TextStyles.bold(
|
|
126
|
-
|
|
127
|
-
)}' contains files that could conflict. Below is a list of conflicts, please remove them and try again.`
|
|
128
|
-
);
|
|
63
|
+
const errorMessageLines = [
|
|
64
|
+
`The directory '${TextStyles.bold(appName)}' contains files that could conflict. Below is a list of conflicts, please remove them and try again.`
|
|
65
|
+
];
|
|
129
66
|
for (const file of conflicts) {
|
|
130
67
|
try {
|
|
131
|
-
const stats =
|
|
68
|
+
const stats = fs.lstatSync(path.join(dir, file));
|
|
132
69
|
if (stats.isDirectory()) {
|
|
133
|
-
|
|
70
|
+
errorMessageLines.push(` - ${TextStyles.info(file)}/`);
|
|
134
71
|
} else {
|
|
135
|
-
|
|
72
|
+
errorMessageLines.push(` - ${file}`);
|
|
136
73
|
}
|
|
137
74
|
} catch {
|
|
138
|
-
|
|
75
|
+
errorMessageLines.push(` - ${file}`);
|
|
139
76
|
}
|
|
140
77
|
}
|
|
141
|
-
|
|
78
|
+
throw new Error(errorMessageLines.join("\n"));
|
|
142
79
|
}
|
|
143
80
|
return appName;
|
|
144
81
|
}
|
|
145
82
|
function updateProjectPackageName(dir, name2) {
|
|
146
|
-
const packageJsonPath =
|
|
147
|
-
const packageJson = JSON.parse(
|
|
83
|
+
const packageJsonPath = path.join(dir, "package.json");
|
|
84
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
148
85
|
packageJson.name = name2;
|
|
149
|
-
|
|
86
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
150
87
|
}
|
|
151
88
|
function updateProjectPackageVersion(dir, version2) {
|
|
152
|
-
const packageJsonPath =
|
|
153
|
-
const packageJson = JSON.parse(
|
|
89
|
+
const packageJsonPath = path.join(dir, "package.json");
|
|
90
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
154
91
|
packageJson.version = version2;
|
|
155
|
-
|
|
92
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
93
|
+
}
|
|
94
|
+
async function updateThemeSettings(dir, selectedTheme) {
|
|
95
|
+
const settingsDir = path.join(dir, "content", "settings");
|
|
96
|
+
const configPath = path.join(settingsDir, "config.json");
|
|
97
|
+
await fs.mkdirp(settingsDir);
|
|
98
|
+
let config = {};
|
|
99
|
+
try {
|
|
100
|
+
const existingConfig = await fs.readFile(configPath, "utf8");
|
|
101
|
+
config = JSON.parse(existingConfig);
|
|
102
|
+
} catch (error) {
|
|
103
|
+
}
|
|
104
|
+
config.selectedTheme = selectedTheme;
|
|
105
|
+
await fs.writeFile(configPath, JSON.stringify(config, null, 2));
|
|
156
106
|
}
|
|
157
107
|
|
|
158
108
|
// src/util/install.ts
|
|
159
|
-
|
|
160
|
-
function install(
|
|
161
|
-
const npmFlags = [];
|
|
162
|
-
const yarnFlags = [];
|
|
163
|
-
const pnpmFlags = [];
|
|
109
|
+
import spawn from "cross-spawn";
|
|
110
|
+
function install(packageManager, verboseOutput) {
|
|
164
111
|
return new Promise((resolve, reject) => {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
if (dependencies == null ? void 0 : dependencies.length) {
|
|
168
|
-
switch (packageManager) {
|
|
169
|
-
case "yarn":
|
|
170
|
-
args = ["add", "--exact"];
|
|
171
|
-
if (!isOnline) args.push("--offline");
|
|
172
|
-
args.push("--cwd", root);
|
|
173
|
-
if (devDependencies) args.push("--dev");
|
|
174
|
-
args.push(...dependencies);
|
|
175
|
-
break;
|
|
176
|
-
case "npm":
|
|
177
|
-
args = ["install", "--save-exact"];
|
|
178
|
-
args.push(devDependencies ? "--save-dev" : "--save");
|
|
179
|
-
args.push(...dependencies);
|
|
180
|
-
break;
|
|
181
|
-
case "pnpm":
|
|
182
|
-
args = ["add"];
|
|
183
|
-
if (!isOnline) args.push("--offline");
|
|
184
|
-
args.push("--save-exact");
|
|
185
|
-
if (devDependencies) args.push("-D");
|
|
186
|
-
args.push(...dependencies);
|
|
187
|
-
break;
|
|
188
|
-
}
|
|
189
|
-
} else {
|
|
190
|
-
args = ["install"];
|
|
191
|
-
if (!isOnline) {
|
|
192
|
-
log.warn("You appear to be offline.");
|
|
193
|
-
if (packageManager === "yarn") {
|
|
194
|
-
log.warn("Falling back to the local Yarn cache.");
|
|
195
|
-
args.push("--offline");
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
switch (packageManager) {
|
|
200
|
-
case "yarn":
|
|
201
|
-
args.push(...yarnFlags);
|
|
202
|
-
break;
|
|
203
|
-
case "npm":
|
|
204
|
-
args.push(...npmFlags);
|
|
205
|
-
break;
|
|
206
|
-
case "pnpm":
|
|
207
|
-
args.push(...pnpmFlags);
|
|
208
|
-
break;
|
|
209
|
-
}
|
|
210
|
-
const child = (0, import_cross_spawn.default)(command, args, {
|
|
211
|
-
stdio: "inherit",
|
|
112
|
+
const child = spawn(packageManager, ["install"], {
|
|
113
|
+
stdio: verboseOutput ? "inherit" : "ignore",
|
|
212
114
|
env: { ...process.env, ADBLOCK: "1", DISABLE_OPENCOLLECTIVE: "1" }
|
|
213
115
|
});
|
|
214
116
|
child.on("close", (code) => {
|
|
215
117
|
if (code !== 0) {
|
|
216
|
-
reject({ command: `${
|
|
118
|
+
reject({ command: `${packageManager} install` });
|
|
217
119
|
return;
|
|
218
120
|
}
|
|
219
121
|
resolve();
|
|
@@ -222,12 +124,12 @@ function install(root, dependencies, { packageManager, isOnline, devDependencies
|
|
|
222
124
|
}
|
|
223
125
|
|
|
224
126
|
// src/util/git.ts
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
127
|
+
import { execSync } from "child_process";
|
|
128
|
+
import path2 from "path";
|
|
129
|
+
import fs2 from "fs-extra";
|
|
228
130
|
function isInGitRepository() {
|
|
229
131
|
try {
|
|
230
|
-
|
|
132
|
+
execSync("git rev-parse --is-inside-work-tree", { stdio: "ignore" });
|
|
231
133
|
return true;
|
|
232
134
|
} catch (_) {
|
|
233
135
|
}
|
|
@@ -235,7 +137,7 @@ function isInGitRepository() {
|
|
|
235
137
|
}
|
|
236
138
|
function isInMercurialRepository() {
|
|
237
139
|
try {
|
|
238
|
-
|
|
140
|
+
execSync("hg --cwd . root", { stdio: "ignore" });
|
|
239
141
|
return true;
|
|
240
142
|
} catch (_) {
|
|
241
143
|
}
|
|
@@ -243,25 +145,27 @@ function isInMercurialRepository() {
|
|
|
243
145
|
}
|
|
244
146
|
function makeFirstCommit(root) {
|
|
245
147
|
try {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
148
|
+
execSync("git checkout -b main", { stdio: "ignore" });
|
|
149
|
+
execSync("git add -A", { stdio: "ignore" });
|
|
150
|
+
execSync('git commit -m "Initial commit from Create Tina App"', {
|
|
249
151
|
stdio: "ignore"
|
|
250
152
|
});
|
|
251
153
|
} catch (err) {
|
|
252
|
-
|
|
154
|
+
fs2.removeSync(path2.join(root, ".git"));
|
|
253
155
|
throw err;
|
|
254
156
|
}
|
|
255
157
|
}
|
|
256
|
-
function initializeGit() {
|
|
257
|
-
|
|
158
|
+
function initializeGit(spinner) {
|
|
159
|
+
execSync("git --version", { stdio: "ignore" });
|
|
258
160
|
if (isInGitRepository() || isInMercurialRepository()) {
|
|
259
|
-
|
|
161
|
+
spinner.warn("Already in a Git repository, skipping.");
|
|
260
162
|
return false;
|
|
261
163
|
}
|
|
262
|
-
if (!
|
|
263
|
-
|
|
264
|
-
|
|
164
|
+
if (!fs2.existsSync(".gitignore")) {
|
|
165
|
+
spinner.warn(
|
|
166
|
+
"There is no .gitignore file in this repository, creating one..."
|
|
167
|
+
);
|
|
168
|
+
fs2.writeFileSync(
|
|
265
169
|
".gitignore",
|
|
266
170
|
`node_modules
|
|
267
171
|
.yarn/*
|
|
@@ -271,14 +175,14 @@ function initializeGit() {
|
|
|
271
175
|
`
|
|
272
176
|
);
|
|
273
177
|
}
|
|
274
|
-
|
|
178
|
+
execSync("git init", { stdio: "ignore" });
|
|
275
179
|
return true;
|
|
276
180
|
}
|
|
277
181
|
|
|
278
182
|
// src/util/examples.ts
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
183
|
+
import { Readable } from "node:stream";
|
|
184
|
+
import { pipeline } from "node:stream/promises";
|
|
185
|
+
import { x } from "tar";
|
|
282
186
|
async function getRepoInfo(url, examplePath) {
|
|
283
187
|
const [, username, name2, t, _branch, ...file] = url.pathname.split("/");
|
|
284
188
|
const filePath = examplePath ? examplePath.replace(/^\//, "") : file.join("/");
|
|
@@ -313,14 +217,14 @@ async function downloadTarStream(url) {
|
|
|
313
217
|
if (!res.body) {
|
|
314
218
|
throw new Error(`Failed to download: ${url}`);
|
|
315
219
|
}
|
|
316
|
-
return
|
|
220
|
+
return Readable.fromWeb(res.body);
|
|
317
221
|
}
|
|
318
222
|
async function downloadAndExtractRepo(root, { username, name: name2, branch, filePath }) {
|
|
319
|
-
await
|
|
223
|
+
await pipeline(
|
|
320
224
|
await downloadTarStream(
|
|
321
225
|
`https://codeload.github.com/${username}/${name2}/tar.gz/${branch}`
|
|
322
226
|
),
|
|
323
|
-
|
|
227
|
+
x({
|
|
324
228
|
cwd: root,
|
|
325
229
|
strip: filePath ? filePath.split("/").length + 1 : 1,
|
|
326
230
|
filter: (p) => p.startsWith(
|
|
@@ -331,96 +235,206 @@ async function downloadAndExtractRepo(root, { username, name: name2, branch, fil
|
|
|
331
235
|
}
|
|
332
236
|
|
|
333
237
|
// src/templates.ts
|
|
334
|
-
|
|
335
|
-
|
|
238
|
+
import { copy } from "fs-extra";
|
|
239
|
+
import path3 from "path";
|
|
336
240
|
var TEMPLATES = [
|
|
337
241
|
{
|
|
338
242
|
title: "\u2B50 NextJS starter",
|
|
339
|
-
description: "Kickstart your project with
|
|
340
|
-
value: "tina-
|
|
243
|
+
description: "Kickstart your project with Next.js \u2013 our top recommendation for a seamless, performant, and versatile web experience.",
|
|
244
|
+
value: "tina-nextjs-starter",
|
|
341
245
|
isInternal: false,
|
|
342
|
-
|
|
246
|
+
features: [
|
|
247
|
+
{
|
|
248
|
+
name: "Visual Editing",
|
|
249
|
+
description: "\u2705"
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
name: "ISR",
|
|
253
|
+
description: "\u2705"
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
name: "SSG",
|
|
257
|
+
description: "\u2705"
|
|
258
|
+
}
|
|
259
|
+
],
|
|
260
|
+
gitURL: "https://github.com/tinacms/tina-nextjs-starter",
|
|
261
|
+
devUrl: "http://localhost:3000"
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
title: "\u2B50\uFE0F TinaDocs",
|
|
265
|
+
description: "Get your documentation site up and running with TinaCMS and Next.js in minutes.",
|
|
266
|
+
value: "tina-docs",
|
|
267
|
+
isInternal: false,
|
|
268
|
+
features: [
|
|
269
|
+
{
|
|
270
|
+
name: "Visual Editing",
|
|
271
|
+
description: "\u2705"
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
name: "ISR",
|
|
275
|
+
description: "\u2705"
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
name: "SSG",
|
|
279
|
+
description: "\u2705"
|
|
280
|
+
}
|
|
281
|
+
],
|
|
282
|
+
gitURL: "https://github.com/tinacms/tina-docs",
|
|
283
|
+
devUrl: "http://localhost:3000"
|
|
343
284
|
},
|
|
344
285
|
{
|
|
345
286
|
title: "Astro Starter",
|
|
346
287
|
description: "Get started with Astro - a modern static site generator designed for fast, lightweight, and flexible web projects.",
|
|
347
288
|
value: "tina-astro-starter",
|
|
348
289
|
isInternal: false,
|
|
349
|
-
|
|
290
|
+
features: [
|
|
291
|
+
{
|
|
292
|
+
name: "Visual Editing",
|
|
293
|
+
description: "\u274C"
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
name: "ISR",
|
|
297
|
+
description: "\u274C"
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
name: "SSG",
|
|
301
|
+
description: "\u2705"
|
|
302
|
+
}
|
|
303
|
+
],
|
|
304
|
+
gitURL: "https://github.com/tinacms/tina-astro-starter",
|
|
305
|
+
devUrl: "http://localhost:4321"
|
|
350
306
|
},
|
|
351
307
|
{
|
|
352
308
|
title: "Hugo Starter",
|
|
353
309
|
description: "With Hugo, you wield the power of lightning-fast site generation, crafting web experiences at the speed of thought.",
|
|
354
310
|
value: "tina-hugo-starter",
|
|
355
311
|
isInternal: false,
|
|
356
|
-
|
|
312
|
+
features: [
|
|
313
|
+
{
|
|
314
|
+
name: "Visual Editing",
|
|
315
|
+
description: "\u274C"
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
name: "ISR",
|
|
319
|
+
description: "\u274C"
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
name: "SSG",
|
|
323
|
+
description: "\u2705"
|
|
324
|
+
}
|
|
325
|
+
],
|
|
326
|
+
gitURL: "https://github.com/tinacms/tina-hugo-starter",
|
|
327
|
+
devUrl: "http://localhost:1313"
|
|
357
328
|
},
|
|
358
329
|
{
|
|
359
330
|
title: "Remix Starter",
|
|
360
331
|
description: "Dive into Remix to orchestrate seamless, interactive user journeys like a maestro of the web.",
|
|
361
332
|
value: "tina-remix-starter",
|
|
362
333
|
isInternal: false,
|
|
363
|
-
|
|
334
|
+
features: [
|
|
335
|
+
{
|
|
336
|
+
name: "Visual Editing",
|
|
337
|
+
description: "\u274C"
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
name: "ISR",
|
|
341
|
+
description: "\u274C"
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
name: "SSG",
|
|
345
|
+
description: "\u26A0\uFE0F Requires adapter"
|
|
346
|
+
}
|
|
347
|
+
],
|
|
348
|
+
gitURL: "https://github.com/tinacms/tina-remix-starter",
|
|
349
|
+
devUrl: "http://localhost:3000"
|
|
364
350
|
},
|
|
365
351
|
{
|
|
366
352
|
title: "Docusaurus Starter",
|
|
367
353
|
description: "Docusaurus empowers you to build and evolve documentation like crafting a living, breathing knowledge repository.",
|
|
368
354
|
value: "tinasaurus",
|
|
369
355
|
isInternal: false,
|
|
370
|
-
|
|
356
|
+
features: [
|
|
357
|
+
{
|
|
358
|
+
name: "Visual Editing",
|
|
359
|
+
description: "\u274C"
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
name: "ISR",
|
|
363
|
+
description: "\u274C"
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
name: "SSR",
|
|
367
|
+
description: "\u2705"
|
|
368
|
+
}
|
|
369
|
+
],
|
|
370
|
+
gitURL: "https://github.com/tinacms/tinasaurus",
|
|
371
|
+
devUrl: "http://localhost:3000"
|
|
371
372
|
},
|
|
372
373
|
{
|
|
373
374
|
title: "Bare bones starter",
|
|
374
|
-
description: "Stripped down to essentials, this starter is the canvas for pure, unadulterated code creativity.",
|
|
375
|
+
description: "Stripped down to essentials, this starter is the canvas for pure, unadulterated code creativity. Built with Next.js.",
|
|
375
376
|
value: "basic",
|
|
376
377
|
isInternal: false,
|
|
377
|
-
|
|
378
|
+
features: [
|
|
379
|
+
{
|
|
380
|
+
name: "Visual Editing",
|
|
381
|
+
description: "\u2705"
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
name: "ISR",
|
|
385
|
+
description: "\u2705"
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
name: "SSG",
|
|
389
|
+
description: "\u2705"
|
|
390
|
+
}
|
|
391
|
+
],
|
|
392
|
+
gitURL: "https://github.com/tinacms/tina-barebones-starter",
|
|
393
|
+
devUrl: "http://localhost:3000"
|
|
378
394
|
}
|
|
379
395
|
];
|
|
380
|
-
async function downloadTemplate(template, root) {
|
|
396
|
+
async function downloadTemplate(template, root, spinner) {
|
|
381
397
|
if (template.isInternal === false) {
|
|
382
398
|
const repoURL = new URL(template.gitURL);
|
|
383
399
|
const repoInfo = await getRepoInfo(repoURL);
|
|
384
400
|
if (!repoInfo) {
|
|
385
401
|
throw new Error("Repository information not found.");
|
|
386
402
|
}
|
|
387
|
-
|
|
388
|
-
`
|
|
389
|
-
|
|
390
|
-
)}.`
|
|
391
|
-
);
|
|
403
|
+
spinner.text = `Downloading files from repo ${TextStyles.tinaOrange(
|
|
404
|
+
`${repoInfo?.username}/${repoInfo?.name}`
|
|
405
|
+
)}`;
|
|
392
406
|
await downloadAndExtractRepo(root, repoInfo);
|
|
393
407
|
} else {
|
|
394
|
-
const templateFile =
|
|
395
|
-
await
|
|
408
|
+
const templateFile = path3.join(__dirname, "..", "examples", template.value);
|
|
409
|
+
await copy(`${templateFile}/`, "./");
|
|
396
410
|
}
|
|
397
411
|
}
|
|
398
412
|
|
|
399
413
|
// src/util/preRunChecks.ts
|
|
400
|
-
var SUPPORTED_NODE_VERSION_BOUNDS = { oldest:
|
|
414
|
+
var SUPPORTED_NODE_VERSION_BOUNDS = { oldest: 20, latest: 22 };
|
|
401
415
|
var SUPPORTED_NODE_VERSION_RANGE = [
|
|
402
416
|
...Array(SUPPORTED_NODE_VERSION_BOUNDS.latest).keys()
|
|
403
417
|
].map((i) => i + SUPPORTED_NODE_VERSION_BOUNDS.oldest);
|
|
404
418
|
var isSupported = SUPPORTED_NODE_VERSION_RANGE.some(
|
|
405
419
|
(version2) => process.version.startsWith(`v${version2}`)
|
|
406
420
|
);
|
|
407
|
-
function preRunChecks() {
|
|
408
|
-
|
|
409
|
-
}
|
|
410
|
-
function checkSupportedNodeVersion() {
|
|
421
|
+
function preRunChecks(spinner) {
|
|
422
|
+
spinner.start("Running pre-run checks...");
|
|
411
423
|
if (!isSupported) {
|
|
412
|
-
|
|
424
|
+
spinner.warn(
|
|
413
425
|
`Node ${process.version} is not supported by create-tina-app. Please update to be within v${SUPPORTED_NODE_VERSION_BOUNDS.oldest}-v${SUPPORTED_NODE_VERSION_BOUNDS.latest}. See https://nodejs.org/en/download/ for more details.`
|
|
414
426
|
);
|
|
427
|
+
} else {
|
|
428
|
+
spinner.succeed(`Node ${process.version} is supported.`);
|
|
415
429
|
}
|
|
416
430
|
}
|
|
417
431
|
|
|
418
432
|
// src/util/checkPkgManagers.ts
|
|
419
|
-
|
|
433
|
+
import { exec } from "child_process";
|
|
420
434
|
async function checkPackageExists(name2) {
|
|
421
435
|
try {
|
|
422
436
|
await new Promise((resolve, reject) => {
|
|
423
|
-
|
|
437
|
+
exec(`${name2} -v`, (error, stdout, stderr) => {
|
|
424
438
|
if (error) {
|
|
425
439
|
reject(stderr);
|
|
426
440
|
}
|
|
@@ -434,13 +448,22 @@ async function checkPackageExists(name2) {
|
|
|
434
448
|
}
|
|
435
449
|
|
|
436
450
|
// src/index.ts
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
451
|
+
import { exit } from "node:process";
|
|
452
|
+
|
|
453
|
+
// src/util/options.ts
|
|
454
|
+
import { Command } from "commander";
|
|
455
|
+
|
|
456
|
+
// package.json
|
|
457
|
+
var name = "create-tina-app";
|
|
458
|
+
var version = "2.0.0";
|
|
459
|
+
|
|
460
|
+
// src/util/packageManagers.ts
|
|
461
|
+
var PKG_MANAGERS = ["npm", "yarn", "pnpm", "bun"];
|
|
462
|
+
|
|
463
|
+
// src/util/options.ts
|
|
464
|
+
function extractOptions(args) {
|
|
442
465
|
let projectName = "";
|
|
443
|
-
const program = new
|
|
466
|
+
const program = new Command(name);
|
|
444
467
|
program.version(version).option(
|
|
445
468
|
"-t, --template <template>",
|
|
446
469
|
`Choose which template to start from. Valid templates are: ${TEMPLATES.map(
|
|
@@ -452,34 +475,212 @@ async function run() {
|
|
|
452
475
|
).option(
|
|
453
476
|
"-d, --dir <dir>",
|
|
454
477
|
"Choose which directory to run this script from."
|
|
455
|
-
).option("--noTelemetry", "Disable anonymous telemetry that is collected.").arguments("[project-directory]").usage(`${TextStyles.success("<project-directory>")} [options]`).action((name2) => {
|
|
478
|
+
).option("-v, --verbose", "Enable verbose output.").option("--noTelemetry", "Disable anonymous telemetry that is collected.").arguments("[project-directory]").usage(`${TextStyles.success("<project-directory>")} [options]`).action((name2) => {
|
|
456
479
|
projectName = name2;
|
|
457
480
|
});
|
|
458
|
-
program.parse(
|
|
481
|
+
program.parse(args);
|
|
459
482
|
const opts = program.opts();
|
|
460
483
|
if (opts.dir) {
|
|
461
484
|
process.chdir(opts.dir);
|
|
462
485
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
486
|
+
if (projectName) {
|
|
487
|
+
opts.projectName = projectName;
|
|
488
|
+
}
|
|
489
|
+
return opts;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// src/util/isNpm.js
|
|
493
|
+
import { builtinModules as builtins } from "node:module";
|
|
494
|
+
function validate(name2) {
|
|
495
|
+
if (name2 === null) {
|
|
496
|
+
return {
|
|
497
|
+
message: "name cannot be null",
|
|
498
|
+
isError: true
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
if (name2 === void 0) {
|
|
502
|
+
return {
|
|
503
|
+
message: "name cannot be undefined",
|
|
504
|
+
isError: true
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
if (typeof name2 !== "string") {
|
|
508
|
+
return {
|
|
509
|
+
message: "name must be a string",
|
|
510
|
+
isError: true
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
if (!name2.length) {
|
|
514
|
+
return {
|
|
515
|
+
message: "name length must be greater than zero",
|
|
516
|
+
isError: true
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
if (name2.startsWith(".")) {
|
|
520
|
+
return {
|
|
521
|
+
message: "name cannot start with a period",
|
|
522
|
+
isError: true
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
if (name2.match(/^_/)) {
|
|
526
|
+
return {
|
|
527
|
+
message: "name cannot start with an underscore",
|
|
528
|
+
isError: true
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
if (name2.trim() !== name2) {
|
|
532
|
+
return {
|
|
533
|
+
message: "name cannot contain leading or trailing spaces",
|
|
534
|
+
isError: true
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
const exclusionList = ["node_modules", "favicon.ico"];
|
|
538
|
+
exclusionList.forEach(function(excludedName) {
|
|
539
|
+
if (name2.toLowerCase() === excludedName) {
|
|
540
|
+
return {
|
|
541
|
+
message: excludedName + " is not a valid package name",
|
|
542
|
+
isError: true
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
});
|
|
546
|
+
if (builtins.includes(name2.toLowerCase())) {
|
|
547
|
+
return {
|
|
548
|
+
message: name2 + " is a core module name",
|
|
549
|
+
isError: true
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
if (name2.length > 214) {
|
|
553
|
+
return {
|
|
554
|
+
message: "name can no longer contain more than 214 characters",
|
|
555
|
+
isError: true
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
if (name2.toLowerCase() !== name2) {
|
|
559
|
+
return {
|
|
560
|
+
message: "name can no longer contain capital letters",
|
|
561
|
+
isError: true
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
if (/[~'!()*]/.test(name2.split("/").slice(-1)[0])) {
|
|
565
|
+
return {
|
|
566
|
+
message: `name can no longer contain special characters ("~'!()*")`,
|
|
567
|
+
isError: true
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
if (encodeURIComponent(name2) !== name2) {
|
|
571
|
+
const scopedPackagePattern = new RegExp("^(?:@([^/]+?)[/])?([^/]+?)$");
|
|
572
|
+
const nameMatch = name2.match(scopedPackagePattern);
|
|
573
|
+
if (nameMatch) {
|
|
574
|
+
const user = nameMatch[1];
|
|
575
|
+
const pkg = nameMatch[2];
|
|
576
|
+
if (pkg.startsWith(".")) {
|
|
577
|
+
return {
|
|
578
|
+
message: "name cannot start with a period",
|
|
579
|
+
isError: true
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
if (encodeURIComponent(user) === user && encodeURIComponent(pkg) === pkg) {
|
|
583
|
+
return { message: null, isError: false };
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
return {
|
|
587
|
+
message: "name can only contain URL-friendly characters",
|
|
588
|
+
isError: true
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
return { message: null, isError: false };
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// src/util/asciiArt.ts
|
|
595
|
+
var llama = " :--=: \n :-===- \n -=====- \n -=======. \n .=========-. \n :===========--:\n -=============.\n .==========-:. \n :=========-. \n -=========- \n .==========- \n -==========- \n :===========- \n -=============. \n :==============: \n :===============- \n .:-================- \n ..::---==================== \n ....::::::::::-------============================. \n .---=================================================: \n .-=====================================================- \n:=======================================================. \n .-====================================================. \n .-=================================================. \n :=============================================- \n -============================================. \n .============-:. -==========- \n :=========-: .. -==========. \n -========: :-=- -=========- \n .========. .-==== :=========: \n -=======: :=====. -========: \n -======- -====- -=======: \n -=====: -====: :======. \n .=====. -====. .-====- \n :==== -===- -====: \n -==- :===- :====. ";
|
|
596
|
+
var errorArt = " ++++++++++++++\u2260 \n +++++++++\u2248 \u03C0+++++++++\u2260 \n ++++ ++++ \n +++ +++\u2248 \n +++ +++ \n \u03C0++ +++ \n ++ ++ \n +- +\u03C0 \n ++\xD7 +++++++++ \u2260+++++++++ \u221A+++++++++ ++ \n + ++ \u2248+++ ++ ++ ++++ +\u221E \n ++ ++ ++ ++ ++ ++ + \n ++ ++ ++ ++ ++ ++ ++ \n ++ ++-+++++++- ++ ++ +++++++- + \n \u221A+ ++\xF7+++++ ++ ++++++++ ++ \n ++ ++ \u221E++ ++ ++ ++ \n ++ ++ +++ ++ ++ ++ \n ++ ++ +++ \u2260+++++++++ ++ \u2260+ \n ++ ++ ++ +\u2260\u221E\u221A\u221A\u2260\xD7+\u03C0 ++ \u2260+ \n ++ \u2260+ \n ++ \u2260+ \n ++ +++ \u2260+ \n ++ ++++ \u2260+ \n ++ ++++++++ \u2260+ \n ++ ++++++++++ =+ \n ++ ++++++ =+ \n ++ \u2248++++++ =+ \n ++ +++++++ \u2260+ \n ++ +++++++ \u2260+ \n ++ +++++++ =+ \n ++ ++++++++ =+ \n ++ \u221E++++++++++++ \u2260+ \n ++ \u221E++++++++++++++++++++++++++++++- =+ \n ++ +++++++++++++++++++++++++++++++++ \u2260+ \n ++ +++++++++++++++++++++++++++++++++ \u2260+ \n ++ ++++++++++++++++++++++++++++++ \u2260+ \n ++ +++++++++++++++++++++++++++++ \u2260+ \n ++ ++++++++++++++++++++++++++++ \u2260+ \n ++ ++++++++\u2260\u2260++++++=\u221A ++++++++ \u2260+ \n ++ ++++++ + +++++++ \u2260+ \n ++ +++++ \u221E+++ \xF7++++++ \u2260+ \n ++ ++++ +++ +++++\u221A \u2260+ \n ++ +++= +++\u221A ++++ \u2260+ \n ++ ++\u221E =++ +++ \u2260+ \n ++ ++\u2248 +++ ++\xF7 =+ \n ++ +++ +++\u2260 +++ =+ \n ++ \u2260+ \n ++ + \n \u2248+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \n ++ +\u2260 \n ++ +++++++++ ++++++++ +++++++ ++++++ ++++++++ +\u2260 \n ++ ++ ++ ++ + ++ ++ ++ ++ ++ +\u2260 \n ++ ++ ++ ++ + ++ ++ ++ ++ ++ +\u2260 \n ++ ++++++++ ++++++++ ++++++++ ++ ++ ++++++++ +\u2260 \n ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +\u2260 \n ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +\u2260 \n ++ +++++++++ ++ ++ ++ ++ +++++++ ++ ++ +\u2260 \n ++ +\u2260 \n ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \n \n ";
|
|
597
|
+
var tinaCms = "\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\n\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\n \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\n \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551\n \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\n \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D";
|
|
598
|
+
|
|
599
|
+
// src/themes.ts
|
|
600
|
+
var THEMES = [
|
|
601
|
+
{
|
|
602
|
+
title: "Default",
|
|
603
|
+
description: "The default monochromatic theme for your documentation site",
|
|
604
|
+
value: "default"
|
|
605
|
+
},
|
|
606
|
+
{
|
|
607
|
+
title: "Tina",
|
|
608
|
+
description: "The warm color scheme of TinaCMS for your documentation",
|
|
609
|
+
value: "tina"
|
|
610
|
+
},
|
|
611
|
+
{
|
|
612
|
+
title: "Blossom",
|
|
613
|
+
value: "blossom",
|
|
614
|
+
description: "A Blossom theme for your project"
|
|
615
|
+
},
|
|
616
|
+
{
|
|
617
|
+
title: "Lake",
|
|
618
|
+
value: "lake",
|
|
619
|
+
description: "A Lake theme for your project"
|
|
620
|
+
},
|
|
621
|
+
{
|
|
622
|
+
title: "Pine",
|
|
623
|
+
value: "pine",
|
|
624
|
+
description: "A Pine theme for your project"
|
|
625
|
+
},
|
|
626
|
+
{
|
|
627
|
+
title: "Indigo",
|
|
628
|
+
value: "indigo",
|
|
629
|
+
description: "An Indigo theme for your project"
|
|
630
|
+
}
|
|
631
|
+
];
|
|
632
|
+
|
|
633
|
+
// src/index.ts
|
|
634
|
+
function formatTemplateChoice(template) {
|
|
635
|
+
let description = template.description || "";
|
|
636
|
+
if (template.features && template.features.length > 0) {
|
|
637
|
+
const featuresText = template.features.map((feature) => ` \u2022 ${feature.name}: ${feature.description}`).join("\n");
|
|
638
|
+
description = `${description}
|
|
639
|
+
|
|
640
|
+
Features:
|
|
641
|
+
${featuresText}`;
|
|
642
|
+
}
|
|
643
|
+
return {
|
|
644
|
+
title: template.title,
|
|
645
|
+
value: template.value,
|
|
646
|
+
description
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
async function run() {
|
|
650
|
+
const ora = (await import("ora")).default;
|
|
651
|
+
let packageManagerInstallationHadError = false;
|
|
652
|
+
if (process.stdout.columns >= 60) {
|
|
653
|
+
console.log(TextStyles.tinaOrange(`${llama}`));
|
|
654
|
+
console.log(TextStyles.tinaOrange(`${tinaCms}`));
|
|
655
|
+
} else {
|
|
656
|
+
console.log(TextStyles.tinaOrange(`\u{1F999} TinaCMS`));
|
|
657
|
+
}
|
|
658
|
+
const require2 = createRequire(import.meta.url);
|
|
659
|
+
const version2 = require2("../package.json").version;
|
|
660
|
+
console.log(`Create Tina App v${version2}`);
|
|
661
|
+
const spinner = ora();
|
|
662
|
+
preRunChecks(spinner);
|
|
663
|
+
const opts = extractOptions(process.argv);
|
|
664
|
+
const telemetry = new Telemetry({ disabled: opts?.noTelemetry });
|
|
665
|
+
let template = null;
|
|
666
|
+
if (opts.template) {
|
|
667
|
+
template = TEMPLATES.find((_template) => _template.value === opts.template);
|
|
467
668
|
if (!template) {
|
|
468
|
-
|
|
669
|
+
spinner.fail(
|
|
469
670
|
`The provided template '${opts.template}' is invalid. Please provide one of the following: ${TEMPLATES.map(
|
|
470
671
|
(x2) => x2.value
|
|
471
672
|
)}`
|
|
472
673
|
);
|
|
473
|
-
|
|
674
|
+
exit(1);
|
|
474
675
|
}
|
|
475
676
|
}
|
|
476
677
|
let pkgManager = opts.pkgManager;
|
|
477
678
|
if (pkgManager) {
|
|
478
679
|
if (!PKG_MANAGERS.find((_pkgManager) => _pkgManager === pkgManager)) {
|
|
479
|
-
|
|
680
|
+
spinner.fail(
|
|
480
681
|
`The provided package manager '${opts.pkgManager}' is not supported. Please provide one of the following: ${PKG_MANAGERS}`
|
|
481
682
|
);
|
|
482
|
-
|
|
683
|
+
exit(1);
|
|
483
684
|
}
|
|
484
685
|
}
|
|
485
686
|
if (!pkgManager) {
|
|
@@ -490,12 +691,12 @@ async function run() {
|
|
|
490
691
|
}
|
|
491
692
|
}
|
|
492
693
|
if (installedPkgManagers.length === 0) {
|
|
493
|
-
|
|
694
|
+
spinner.fail(
|
|
494
695
|
`You have no supported package managers installed. Please install one of the following: ${PKG_MANAGERS}`
|
|
495
696
|
);
|
|
496
|
-
|
|
697
|
+
exit(1);
|
|
497
698
|
}
|
|
498
|
-
const res = await (
|
|
699
|
+
const res = await prompts({
|
|
499
700
|
message: "Which package manager would you like to use?",
|
|
500
701
|
name: "packageManager",
|
|
501
702
|
type: "select",
|
|
@@ -503,91 +704,151 @@ async function run() {
|
|
|
503
704
|
return { title: manager, value: manager };
|
|
504
705
|
})
|
|
505
706
|
});
|
|
506
|
-
if (!Object.hasOwn(res, "packageManager"))
|
|
707
|
+
if (!Object.hasOwn(res, "packageManager")) exit(1);
|
|
507
708
|
pkgManager = res.packageManager;
|
|
508
709
|
}
|
|
710
|
+
let projectName = opts.projectName;
|
|
509
711
|
if (!projectName) {
|
|
510
|
-
const res = await (
|
|
712
|
+
const res = await prompts({
|
|
511
713
|
name: "name",
|
|
512
714
|
type: "text",
|
|
513
715
|
message: "What is your project named?",
|
|
514
716
|
initial: "my-tina-app",
|
|
515
717
|
validate: (name2) => {
|
|
516
|
-
const {
|
|
517
|
-
|
|
718
|
+
const { message, isError } = validate(
|
|
719
|
+
path4.basename(path4.resolve(name2))
|
|
518
720
|
);
|
|
519
|
-
if (
|
|
520
|
-
return
|
|
721
|
+
if (isError) return `Invalid project name: ${message}`;
|
|
722
|
+
return true;
|
|
521
723
|
}
|
|
522
724
|
});
|
|
523
|
-
if (!Object.hasOwn(res, "name"))
|
|
725
|
+
if (!Object.hasOwn(res, "name")) exit(1);
|
|
524
726
|
projectName = res.name;
|
|
525
727
|
}
|
|
526
728
|
if (!template) {
|
|
527
|
-
const res = await (
|
|
729
|
+
const res = await prompts({
|
|
528
730
|
name: "template",
|
|
529
731
|
type: "select",
|
|
530
732
|
message: "What starter code would you like to use?",
|
|
531
|
-
choices: TEMPLATES
|
|
733
|
+
choices: TEMPLATES.map(formatTemplateChoice)
|
|
532
734
|
});
|
|
533
|
-
if (!Object.hasOwn(res, "template"))
|
|
735
|
+
if (!Object.hasOwn(res, "template")) exit(1);
|
|
534
736
|
template = TEMPLATES.find((_template) => _template.value === res.template);
|
|
535
737
|
}
|
|
738
|
+
let themeChoice;
|
|
739
|
+
if (template.value === "tina-docs") {
|
|
740
|
+
const res = await prompts({
|
|
741
|
+
name: "theme",
|
|
742
|
+
type: "select",
|
|
743
|
+
message: "What theme would you like to use?",
|
|
744
|
+
choices: THEMES
|
|
745
|
+
});
|
|
746
|
+
if (!Object.hasOwn(res, "theme")) exit(1);
|
|
747
|
+
themeChoice = res.theme;
|
|
748
|
+
}
|
|
536
749
|
await telemetry.submitRecord({
|
|
537
750
|
event: {
|
|
538
751
|
name: "create-tina-app:invoke",
|
|
539
|
-
template,
|
|
752
|
+
template: template.value,
|
|
540
753
|
pkgManager
|
|
541
754
|
}
|
|
542
755
|
});
|
|
543
|
-
const rootDir =
|
|
544
|
-
if (!await isWriteable(
|
|
545
|
-
|
|
756
|
+
const rootDir = path4.join(process.cwd(), projectName);
|
|
757
|
+
if (!await isWriteable(path4.dirname(rootDir))) {
|
|
758
|
+
spinner.fail(
|
|
546
759
|
"The application path is not writable, please check folder permissions and try again. It is likely you do not have write permissions for this folder."
|
|
547
760
|
);
|
|
548
761
|
process.exit(1);
|
|
549
762
|
}
|
|
550
|
-
|
|
763
|
+
let appName;
|
|
764
|
+
try {
|
|
765
|
+
appName = await setupProjectDirectory(rootDir);
|
|
766
|
+
} catch (err) {
|
|
767
|
+
spinner.fail(err.message);
|
|
768
|
+
exit(1);
|
|
769
|
+
}
|
|
551
770
|
try {
|
|
552
|
-
await downloadTemplate(template, rootDir);
|
|
771
|
+
await downloadTemplate(template, rootDir, spinner);
|
|
772
|
+
if (themeChoice) {
|
|
773
|
+
await updateThemeSettings(rootDir, themeChoice);
|
|
774
|
+
}
|
|
775
|
+
spinner.start("Downloading template...");
|
|
776
|
+
await downloadTemplate(template, rootDir, spinner);
|
|
777
|
+
spinner.succeed();
|
|
778
|
+
spinner.start("Updating project metadata...");
|
|
553
779
|
updateProjectPackageName(rootDir, projectName);
|
|
554
780
|
updateProjectPackageVersion(rootDir, "0.0.1");
|
|
781
|
+
spinner.succeed();
|
|
782
|
+
} catch (err) {
|
|
783
|
+
spinner.fail(`Failed to download template: ${err.message}`);
|
|
784
|
+
exit(1);
|
|
785
|
+
}
|
|
786
|
+
spinner.start("Installing packages.");
|
|
787
|
+
try {
|
|
788
|
+
await install(pkgManager, opts.verbose);
|
|
789
|
+
spinner.succeed();
|
|
555
790
|
} catch (err) {
|
|
556
|
-
|
|
557
|
-
|
|
791
|
+
spinner.fail(`Failed to install packages: ${err.message}`);
|
|
792
|
+
packageManagerInstallationHadError = true;
|
|
558
793
|
}
|
|
559
|
-
|
|
560
|
-
await install(rootDir, null, { packageManager: pkgManager, isOnline: true });
|
|
561
|
-
log.info("Initializing git repository.");
|
|
794
|
+
spinner.start("Initializing git repository.");
|
|
562
795
|
try {
|
|
563
|
-
if (initializeGit()) {
|
|
796
|
+
if (initializeGit(spinner)) {
|
|
564
797
|
makeFirstCommit(rootDir);
|
|
565
|
-
|
|
798
|
+
spinner.succeed();
|
|
566
799
|
}
|
|
567
800
|
} catch (err) {
|
|
568
|
-
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
801
|
+
spinner.fail("Failed to initialize Git repository, skipping.");
|
|
802
|
+
}
|
|
803
|
+
spinner.succeed(`Created ${TextStyles.tinaOrange(appName)}
|
|
804
|
+
`);
|
|
805
|
+
if (template.value === "tina-hugo-starter") {
|
|
806
|
+
spinner.warn(
|
|
807
|
+
`Hugo is required for this starter. Install it via ${TextStyles.link(
|
|
808
|
+
"https://gohugo.io/installation/"
|
|
809
|
+
)}
|
|
810
|
+
`
|
|
811
|
+
);
|
|
812
|
+
}
|
|
813
|
+
const padCommand = (cmd, width = 20) => TextStyles.cmd(cmd) + " ".repeat(Math.max(0, width - cmd.length));
|
|
814
|
+
spinner.info(`${TextStyles.bold("To get started:")}
|
|
815
|
+
|
|
816
|
+
${padCommand(`cd ${appName}`)}# move into your project directory${packageManagerInstallationHadError ? `
|
|
817
|
+
${padCommand(`${pkgManager} install`)}# install dependencies` : ""}
|
|
818
|
+
${padCommand(
|
|
819
|
+
`${pkgManager} run dev`
|
|
820
|
+
)}# start the dev server ${TextStyles.link(template.devUrl)}
|
|
821
|
+
${padCommand(`${pkgManager} run build`)}# build the app for production
|
|
822
|
+
`);
|
|
823
|
+
console.log("Next steps:");
|
|
824
|
+
console.log(
|
|
825
|
+
` \u2022 \u{1F4DD} Edit some content: ${TextStyles.link(
|
|
826
|
+
"https://tina.io/docs/using-tina-editor"
|
|
827
|
+
)}`
|
|
828
|
+
);
|
|
829
|
+
console.log(
|
|
830
|
+
` \u2022 \u{1F4D6} Learn the basics: ${TextStyles.link(
|
|
831
|
+
"https://tina.io/docs/schema/"
|
|
832
|
+
)}`
|
|
833
|
+
);
|
|
834
|
+
console.log(
|
|
835
|
+
` \u2022 \u{1F58C}\uFE0F Extend Tina with custom field components: ${TextStyles.link(
|
|
836
|
+
"https://tina.io/docs/advanced/extending-tina/"
|
|
837
|
+
)}`
|
|
838
|
+
);
|
|
839
|
+
console.log(
|
|
840
|
+
` \u2022 \u{1F680} Deploy to Production: ${TextStyles.link(
|
|
841
|
+
"https://tina.io/docs/tinacloud/"
|
|
842
|
+
)}`
|
|
843
|
+
);
|
|
587
844
|
}
|
|
588
|
-
run()
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
845
|
+
run().catch((error) => {
|
|
846
|
+
if (process.stdout.columns >= 60) {
|
|
847
|
+
console.log(TextStyles.tinaOrange(`${errorArt}`));
|
|
848
|
+
}
|
|
849
|
+
console.error("Error running create-tina-app: \n", error);
|
|
850
|
+
process.exit(1);
|
|
593
851
|
});
|
|
852
|
+
export {
|
|
853
|
+
run
|
|
854
|
+
};
|
package/dist/templates.d.ts
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
import { Ora } from 'ora';
|
|
2
|
+
type Feature = {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
};
|
|
6
|
+
export type BaseExample = {
|
|
2
7
|
title: string;
|
|
3
8
|
description?: string;
|
|
9
|
+
features?: Feature[];
|
|
4
10
|
value: string;
|
|
11
|
+
devUrl: string;
|
|
5
12
|
};
|
|
6
13
|
export type InternalTemplate = BaseExample & {
|
|
7
14
|
isInternal: true;
|
|
@@ -12,5 +19,5 @@ export type ExternalTemplate = BaseExample & {
|
|
|
12
19
|
};
|
|
13
20
|
export type Template = InternalTemplate | ExternalTemplate;
|
|
14
21
|
export declare const TEMPLATES: Template[];
|
|
15
|
-
export declare function downloadTemplate(template: Template, root: string): Promise<void>;
|
|
22
|
+
export declare function downloadTemplate(template: Template, root: string, spinner: Ora): Promise<void>;
|
|
16
23
|
export {};
|
package/dist/themes.d.ts
ADDED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare function checkPackageExists(name:
|
|
1
|
+
import { PackageManager } from './packageManagers';
|
|
2
|
+
export declare function checkPackageExists(name: PackageManager): Promise<boolean>;
|
package/dist/util/fileUtil.d.ts
CHANGED
|
@@ -3,3 +3,4 @@ export declare function folderContainsInstallConflicts(root: string): string[];
|
|
|
3
3
|
export declare function setupProjectDirectory(dir: string): Promise<string>;
|
|
4
4
|
export declare function updateProjectPackageName(dir: string, name: string): void;
|
|
5
5
|
export declare function updateProjectPackageVersion(dir: string, version: string): void;
|
|
6
|
+
export declare function updateThemeSettings(dir: string, selectedTheme: string): Promise<void>;
|
package/dist/util/git.d.ts
CHANGED
package/dist/util/install.d.ts
CHANGED
|
@@ -1,21 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* The package manager to use (yarn, npm, pnpm).
|
|
4
|
-
*/
|
|
5
|
-
packageManager: 'yarn' | 'npm' | 'pnpm';
|
|
6
|
-
/**
|
|
7
|
-
* Indicate whether there is an active Internet connection.
|
|
8
|
-
*/
|
|
9
|
-
isOnline: boolean;
|
|
10
|
-
/**
|
|
11
|
-
* Indicate whether the given dependencies are devDependencies.
|
|
12
|
-
*/
|
|
13
|
-
devDependencies?: boolean;
|
|
14
|
-
}
|
|
1
|
+
import { PackageManager } from './packageManagers';
|
|
15
2
|
/**
|
|
16
|
-
* Spawn a package manager installation
|
|
3
|
+
* Spawn a package manager installation.
|
|
17
4
|
*
|
|
18
5
|
* @returns A Promise that resolves once the installation is finished.
|
|
19
6
|
*/
|
|
20
|
-
export declare function install(
|
|
21
|
-
export {};
|
|
7
|
+
export declare function install(packageManager: PackageManager, verboseOutput: boolean): Promise<void>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Object} ValidationResult
|
|
3
|
+
* @property {string | null} message
|
|
4
|
+
* @property {boolean} isError
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Validates whether the provided name is valid on NPM.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} name
|
|
10
|
+
* @returns {ValidationResult}
|
|
11
|
+
*/
|
|
12
|
+
export default function validate(name: string): ValidationResult;
|
|
13
|
+
export type ValidationResult = {
|
|
14
|
+
message: string | null;
|
|
15
|
+
isError: boolean;
|
|
16
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The available package managers a user can use.
|
|
3
|
+
* To add a new supported package manager, add the usage command to this list.
|
|
4
|
+
* The `PackageManager` type will be automatically updated as a result.
|
|
5
|
+
*/
|
|
6
|
+
export declare const PKG_MANAGERS: readonly ["npm", "yarn", "pnpm", "bun"];
|
|
7
|
+
export type PackageManager = (typeof PKG_MANAGERS)[number];
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import { Ora } from 'ora';
|
|
2
|
+
export declare function preRunChecks(spinner: Ora): void;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const TextStyles: {
|
|
2
|
+
tinaOrange: import("chalk").ChalkInstance;
|
|
3
|
+
link: (url: string) => string;
|
|
4
|
+
cmd: import("chalk").ChalkInstance;
|
|
5
|
+
info: import("chalk").ChalkInstance;
|
|
6
|
+
success: import("chalk").ChalkInstance;
|
|
7
|
+
warn: import("chalk").ChalkInstance;
|
|
8
|
+
err: import("chalk").ChalkInstance;
|
|
9
|
+
bold: import("chalk").ChalkInstance;
|
|
10
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-tina-app",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-d813ac1-20251210222143",
|
|
4
|
+
"type": "module",
|
|
4
5
|
"main": "dist/index.js",
|
|
5
6
|
"files": [
|
|
6
7
|
"dist",
|
|
@@ -35,17 +36,17 @@
|
|
|
35
36
|
"@types/prompts": "^2.4.9",
|
|
36
37
|
"@types/tar": "6.1.13",
|
|
37
38
|
"typescript": "^5.7.3",
|
|
38
|
-
"@tinacms/scripts": "
|
|
39
|
+
"@tinacms/scripts": "1.4.2"
|
|
39
40
|
},
|
|
40
41
|
"dependencies": {
|
|
41
|
-
"chalk": "4.1
|
|
42
|
+
"chalk": "^5.4.1",
|
|
42
43
|
"commander": "^12.1.0",
|
|
43
44
|
"cross-spawn": "^7.0.6",
|
|
44
45
|
"fs-extra": "^11.3.0",
|
|
46
|
+
"ora": "^8.2.0",
|
|
45
47
|
"prompts": "^2.4.2",
|
|
46
48
|
"tar": "7.4.0",
|
|
47
|
-
"
|
|
48
|
-
"@tinacms/metrics": "0.0.0-d7c5ec1-20250219020924"
|
|
49
|
+
"@tinacms/metrics": "2.0.1"
|
|
49
50
|
},
|
|
50
51
|
"scripts": {
|
|
51
52
|
"types": "pnpm tsc",
|
package/dist/util/logger.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
export declare const TextStyles: {
|
|
3
|
-
link: chalk.Chalk;
|
|
4
|
-
cmd: chalk.Chalk;
|
|
5
|
-
info: chalk.Chalk;
|
|
6
|
-
success: chalk.Chalk;
|
|
7
|
-
warn: chalk.Chalk;
|
|
8
|
-
err: chalk.Chalk;
|
|
9
|
-
bold: chalk.Chalk;
|
|
10
|
-
};
|
|
11
|
-
export declare class Logger {
|
|
12
|
-
log(message: string): void;
|
|
13
|
-
debug(message: string): void;
|
|
14
|
-
info(message: string): void;
|
|
15
|
-
success(message: string): void;
|
|
16
|
-
cmd(message: string): void;
|
|
17
|
-
warn(message: string): void;
|
|
18
|
-
err(message: string): void;
|
|
19
|
-
}
|
|
20
|
-
export declare const log: Logger;
|