create-tina-app 0.0.0-ddc5e8e-20250611011547 → 0.0.0-e1eb9ad-20251211011556
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 -8
- package/dist/index.js +522 -215
- 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 +1 -1
- package/dist/util/fileUtil.d.ts +1 -0
- package/dist/util/git.d.ts +2 -1
- package/dist/util/install.d.ts +2 -2
- 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
|
@@ -1,9 +1 @@
|
|
|
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
|
-
declare const PKG_MANAGERS: readonly ["npm", "yarn", "pnpm", "bun"];
|
|
7
|
-
export type PackageManager = (typeof PKG_MANAGERS)[number];
|
|
8
1
|
export declare function run(): Promise<void>;
|
|
9
|
-
export {};
|
package/dist/index.js
CHANGED
|
@@ -1,90 +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
|
-
module.exports = __toCommonJS(index_exports);
|
|
35
|
-
var import_metrics = require("@tinacms/metrics");
|
|
36
|
-
var import_commander = require("commander");
|
|
37
|
-
var import_prompts = __toESM(require("prompts"));
|
|
38
|
-
var import_node_path = __toESM(require("node:path"));
|
|
39
|
-
|
|
40
|
-
// package.json
|
|
41
|
-
var name = "create-tina-app";
|
|
42
|
-
var version = "1.3.4";
|
|
2
|
+
import { Telemetry } from "@tinacms/metrics";
|
|
3
|
+
import prompts from "prompts";
|
|
4
|
+
import path4 from "node:path";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
43
6
|
|
|
44
7
|
// src/util/fileUtil.ts
|
|
45
|
-
|
|
46
|
-
|
|
8
|
+
import fs from "fs-extra";
|
|
9
|
+
import path from "path";
|
|
47
10
|
|
|
48
|
-
// src/util/
|
|
49
|
-
|
|
11
|
+
// src/util/textstyles.ts
|
|
12
|
+
import chalk from "chalk";
|
|
50
13
|
var TextStyles = {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
var Logger = class {
|
|
60
|
-
log(message) {
|
|
61
|
-
console.info(message);
|
|
62
|
-
}
|
|
63
|
-
debug(message) {
|
|
64
|
-
console.debug(TextStyles.info(`[DEBUG] ${message}`));
|
|
65
|
-
}
|
|
66
|
-
info(message) {
|
|
67
|
-
console.info(TextStyles.info(`[INFO] ${message}`));
|
|
68
|
-
}
|
|
69
|
-
success(message) {
|
|
70
|
-
console.log(TextStyles.success(`[SUCCESS] ${message}`));
|
|
71
|
-
}
|
|
72
|
-
cmd(message) {
|
|
73
|
-
console.log(TextStyles.cmd(message));
|
|
74
|
-
}
|
|
75
|
-
warn(message) {
|
|
76
|
-
console.warn(TextStyles.warn(`[WARNING] ${message}`));
|
|
77
|
-
}
|
|
78
|
-
err(message) {
|
|
79
|
-
console.error(TextStyles.err(`[ERROR] ${message}`));
|
|
80
|
-
}
|
|
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
|
|
81
22
|
};
|
|
82
|
-
var log = new Logger();
|
|
83
23
|
|
|
84
24
|
// src/util/fileUtil.ts
|
|
85
25
|
async function isWriteable(directory) {
|
|
86
26
|
try {
|
|
87
|
-
await
|
|
27
|
+
await fs.promises.access(directory, (fs.constants || fs).W_OK);
|
|
88
28
|
return true;
|
|
89
29
|
} catch (err) {
|
|
90
30
|
return false;
|
|
@@ -111,55 +51,66 @@ function folderContainsInstallConflicts(root) {
|
|
|
111
51
|
"yarn-debug.log",
|
|
112
52
|
"yarn-error.log"
|
|
113
53
|
];
|
|
114
|
-
const conflicts =
|
|
54
|
+
const conflicts = fs.readdirSync(root).filter((file) => !validFiles.includes(file)).filter((file) => !/\.iml$/.test(file));
|
|
115
55
|
return conflicts;
|
|
116
56
|
}
|
|
117
57
|
async function setupProjectDirectory(dir) {
|
|
118
|
-
const appName =
|
|
119
|
-
await
|
|
58
|
+
const appName = path.basename(dir);
|
|
59
|
+
await fs.mkdirp(dir);
|
|
120
60
|
process.chdir(dir);
|
|
121
61
|
const conflicts = folderContainsInstallConflicts(dir);
|
|
122
62
|
if (conflicts.length > 0) {
|
|
123
|
-
|
|
124
|
-
`The directory '${TextStyles.bold(
|
|
125
|
-
|
|
126
|
-
)}' contains files that could conflict. Below is a list of conflicts, please remove them and try again.`
|
|
127
|
-
);
|
|
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
|
+
];
|
|
128
66
|
for (const file of conflicts) {
|
|
129
67
|
try {
|
|
130
|
-
const stats =
|
|
68
|
+
const stats = fs.lstatSync(path.join(dir, file));
|
|
131
69
|
if (stats.isDirectory()) {
|
|
132
|
-
|
|
70
|
+
errorMessageLines.push(` - ${TextStyles.info(file)}/`);
|
|
133
71
|
} else {
|
|
134
|
-
|
|
72
|
+
errorMessageLines.push(` - ${file}`);
|
|
135
73
|
}
|
|
136
74
|
} catch {
|
|
137
|
-
|
|
75
|
+
errorMessageLines.push(` - ${file}`);
|
|
138
76
|
}
|
|
139
77
|
}
|
|
140
|
-
|
|
78
|
+
throw new Error(errorMessageLines.join("\n"));
|
|
141
79
|
}
|
|
142
80
|
return appName;
|
|
143
81
|
}
|
|
144
82
|
function updateProjectPackageName(dir, name2) {
|
|
145
|
-
const packageJsonPath =
|
|
146
|
-
const packageJson = JSON.parse(
|
|
83
|
+
const packageJsonPath = path.join(dir, "package.json");
|
|
84
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
147
85
|
packageJson.name = name2;
|
|
148
|
-
|
|
86
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
149
87
|
}
|
|
150
88
|
function updateProjectPackageVersion(dir, version2) {
|
|
151
|
-
const packageJsonPath =
|
|
152
|
-
const packageJson = JSON.parse(
|
|
89
|
+
const packageJsonPath = path.join(dir, "package.json");
|
|
90
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
153
91
|
packageJson.version = version2;
|
|
154
|
-
|
|
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));
|
|
155
106
|
}
|
|
156
107
|
|
|
157
108
|
// src/util/install.ts
|
|
158
|
-
|
|
159
|
-
function install(packageManager) {
|
|
109
|
+
import spawn from "cross-spawn";
|
|
110
|
+
function install(packageManager, verboseOutput) {
|
|
160
111
|
return new Promise((resolve, reject) => {
|
|
161
|
-
const child = (
|
|
162
|
-
stdio: "inherit",
|
|
112
|
+
const child = spawn(packageManager, ["install"], {
|
|
113
|
+
stdio: verboseOutput ? "inherit" : "ignore",
|
|
163
114
|
env: { ...process.env, ADBLOCK: "1", DISABLE_OPENCOLLECTIVE: "1" }
|
|
164
115
|
});
|
|
165
116
|
child.on("close", (code) => {
|
|
@@ -173,12 +124,12 @@ function install(packageManager) {
|
|
|
173
124
|
}
|
|
174
125
|
|
|
175
126
|
// src/util/git.ts
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
127
|
+
import { execSync } from "child_process";
|
|
128
|
+
import path2 from "path";
|
|
129
|
+
import fs2 from "fs-extra";
|
|
179
130
|
function isInGitRepository() {
|
|
180
131
|
try {
|
|
181
|
-
|
|
132
|
+
execSync("git rev-parse --is-inside-work-tree", { stdio: "ignore" });
|
|
182
133
|
return true;
|
|
183
134
|
} catch (_) {
|
|
184
135
|
}
|
|
@@ -186,7 +137,7 @@ function isInGitRepository() {
|
|
|
186
137
|
}
|
|
187
138
|
function isInMercurialRepository() {
|
|
188
139
|
try {
|
|
189
|
-
|
|
140
|
+
execSync("hg --cwd . root", { stdio: "ignore" });
|
|
190
141
|
return true;
|
|
191
142
|
} catch (_) {
|
|
192
143
|
}
|
|
@@ -194,25 +145,27 @@ function isInMercurialRepository() {
|
|
|
194
145
|
}
|
|
195
146
|
function makeFirstCommit(root) {
|
|
196
147
|
try {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
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"', {
|
|
200
151
|
stdio: "ignore"
|
|
201
152
|
});
|
|
202
153
|
} catch (err) {
|
|
203
|
-
|
|
154
|
+
fs2.removeSync(path2.join(root, ".git"));
|
|
204
155
|
throw err;
|
|
205
156
|
}
|
|
206
157
|
}
|
|
207
|
-
function initializeGit() {
|
|
208
|
-
|
|
158
|
+
function initializeGit(spinner) {
|
|
159
|
+
execSync("git --version", { stdio: "ignore" });
|
|
209
160
|
if (isInGitRepository() || isInMercurialRepository()) {
|
|
210
|
-
|
|
161
|
+
spinner.warn("Already in a Git repository, skipping.");
|
|
211
162
|
return false;
|
|
212
163
|
}
|
|
213
|
-
if (!
|
|
214
|
-
|
|
215
|
-
|
|
164
|
+
if (!fs2.existsSync(".gitignore")) {
|
|
165
|
+
spinner.warn(
|
|
166
|
+
"There is no .gitignore file in this repository, creating one..."
|
|
167
|
+
);
|
|
168
|
+
fs2.writeFileSync(
|
|
216
169
|
".gitignore",
|
|
217
170
|
`node_modules
|
|
218
171
|
.yarn/*
|
|
@@ -222,14 +175,14 @@ function initializeGit() {
|
|
|
222
175
|
`
|
|
223
176
|
);
|
|
224
177
|
}
|
|
225
|
-
|
|
178
|
+
execSync("git init", { stdio: "ignore" });
|
|
226
179
|
return true;
|
|
227
180
|
}
|
|
228
181
|
|
|
229
182
|
// src/util/examples.ts
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
183
|
+
import { Readable } from "node:stream";
|
|
184
|
+
import { pipeline } from "node:stream/promises";
|
|
185
|
+
import { x } from "tar";
|
|
233
186
|
async function getRepoInfo(url, examplePath) {
|
|
234
187
|
const [, username, name2, t, _branch, ...file] = url.pathname.split("/");
|
|
235
188
|
const filePath = examplePath ? examplePath.replace(/^\//, "") : file.join("/");
|
|
@@ -264,14 +217,14 @@ async function downloadTarStream(url) {
|
|
|
264
217
|
if (!res.body) {
|
|
265
218
|
throw new Error(`Failed to download: ${url}`);
|
|
266
219
|
}
|
|
267
|
-
return
|
|
220
|
+
return Readable.fromWeb(res.body);
|
|
268
221
|
}
|
|
269
222
|
async function downloadAndExtractRepo(root, { username, name: name2, branch, filePath }) {
|
|
270
|
-
await
|
|
223
|
+
await pipeline(
|
|
271
224
|
await downloadTarStream(
|
|
272
225
|
`https://codeload.github.com/${username}/${name2}/tar.gz/${branch}`
|
|
273
226
|
),
|
|
274
|
-
|
|
227
|
+
x({
|
|
275
228
|
cwd: root,
|
|
276
229
|
strip: filePath ? filePath.split("/").length + 1 : 1,
|
|
277
230
|
filter: (p) => p.startsWith(
|
|
@@ -282,96 +235,206 @@ async function downloadAndExtractRepo(root, { username, name: name2, branch, fil
|
|
|
282
235
|
}
|
|
283
236
|
|
|
284
237
|
// src/templates.ts
|
|
285
|
-
|
|
286
|
-
|
|
238
|
+
import { copy } from "fs-extra";
|
|
239
|
+
import path3 from "path";
|
|
287
240
|
var TEMPLATES = [
|
|
288
241
|
{
|
|
289
242
|
title: "\u2B50 NextJS starter",
|
|
290
|
-
description: "Kickstart your project with
|
|
291
|
-
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",
|
|
292
245
|
isInternal: false,
|
|
293
|
-
|
|
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"
|
|
294
284
|
},
|
|
295
285
|
{
|
|
296
286
|
title: "Astro Starter",
|
|
297
287
|
description: "Get started with Astro - a modern static site generator designed for fast, lightweight, and flexible web projects.",
|
|
298
288
|
value: "tina-astro-starter",
|
|
299
289
|
isInternal: false,
|
|
300
|
-
|
|
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"
|
|
301
306
|
},
|
|
302
307
|
{
|
|
303
308
|
title: "Hugo Starter",
|
|
304
309
|
description: "With Hugo, you wield the power of lightning-fast site generation, crafting web experiences at the speed of thought.",
|
|
305
310
|
value: "tina-hugo-starter",
|
|
306
311
|
isInternal: false,
|
|
307
|
-
|
|
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"
|
|
308
328
|
},
|
|
309
329
|
{
|
|
310
330
|
title: "Remix Starter",
|
|
311
331
|
description: "Dive into Remix to orchestrate seamless, interactive user journeys like a maestro of the web.",
|
|
312
332
|
value: "tina-remix-starter",
|
|
313
333
|
isInternal: false,
|
|
314
|
-
|
|
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"
|
|
315
350
|
},
|
|
316
351
|
{
|
|
317
352
|
title: "Docusaurus Starter",
|
|
318
353
|
description: "Docusaurus empowers you to build and evolve documentation like crafting a living, breathing knowledge repository.",
|
|
319
354
|
value: "tinasaurus",
|
|
320
355
|
isInternal: false,
|
|
321
|
-
|
|
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"
|
|
322
372
|
},
|
|
323
373
|
{
|
|
324
374
|
title: "Bare bones starter",
|
|
325
|
-
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.",
|
|
326
376
|
value: "basic",
|
|
327
377
|
isInternal: false,
|
|
328
|
-
|
|
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"
|
|
329
394
|
}
|
|
330
395
|
];
|
|
331
|
-
async function downloadTemplate(template, root) {
|
|
396
|
+
async function downloadTemplate(template, root, spinner) {
|
|
332
397
|
if (template.isInternal === false) {
|
|
333
398
|
const repoURL = new URL(template.gitURL);
|
|
334
399
|
const repoInfo = await getRepoInfo(repoURL);
|
|
335
400
|
if (!repoInfo) {
|
|
336
401
|
throw new Error("Repository information not found.");
|
|
337
402
|
}
|
|
338
|
-
|
|
339
|
-
`
|
|
340
|
-
|
|
341
|
-
)}.`
|
|
342
|
-
);
|
|
403
|
+
spinner.text = `Downloading files from repo ${TextStyles.tinaOrange(
|
|
404
|
+
`${repoInfo?.username}/${repoInfo?.name}`
|
|
405
|
+
)}`;
|
|
343
406
|
await downloadAndExtractRepo(root, repoInfo);
|
|
344
407
|
} else {
|
|
345
|
-
const templateFile =
|
|
346
|
-
await
|
|
408
|
+
const templateFile = path3.join(__dirname, "..", "examples", template.value);
|
|
409
|
+
await copy(`${templateFile}/`, "./");
|
|
347
410
|
}
|
|
348
411
|
}
|
|
349
412
|
|
|
350
413
|
// src/util/preRunChecks.ts
|
|
351
|
-
var SUPPORTED_NODE_VERSION_BOUNDS = { oldest:
|
|
414
|
+
var SUPPORTED_NODE_VERSION_BOUNDS = { oldest: 20, latest: 22 };
|
|
352
415
|
var SUPPORTED_NODE_VERSION_RANGE = [
|
|
353
416
|
...Array(SUPPORTED_NODE_VERSION_BOUNDS.latest).keys()
|
|
354
417
|
].map((i) => i + SUPPORTED_NODE_VERSION_BOUNDS.oldest);
|
|
355
418
|
var isSupported = SUPPORTED_NODE_VERSION_RANGE.some(
|
|
356
419
|
(version2) => process.version.startsWith(`v${version2}`)
|
|
357
420
|
);
|
|
358
|
-
function preRunChecks() {
|
|
359
|
-
|
|
360
|
-
}
|
|
361
|
-
function checkSupportedNodeVersion() {
|
|
421
|
+
function preRunChecks(spinner) {
|
|
422
|
+
spinner.start("Running pre-run checks...");
|
|
362
423
|
if (!isSupported) {
|
|
363
|
-
|
|
424
|
+
spinner.warn(
|
|
364
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.`
|
|
365
426
|
);
|
|
427
|
+
} else {
|
|
428
|
+
spinner.succeed(`Node ${process.version} is supported.`);
|
|
366
429
|
}
|
|
367
430
|
}
|
|
368
431
|
|
|
369
432
|
// src/util/checkPkgManagers.ts
|
|
370
|
-
|
|
433
|
+
import { exec } from "child_process";
|
|
371
434
|
async function checkPackageExists(name2) {
|
|
372
435
|
try {
|
|
373
436
|
await new Promise((resolve, reject) => {
|
|
374
|
-
|
|
437
|
+
exec(`${name2} -v`, (error, stdout, stderr) => {
|
|
375
438
|
if (error) {
|
|
376
439
|
reject(stderr);
|
|
377
440
|
}
|
|
@@ -385,13 +448,22 @@ async function checkPackageExists(name2) {
|
|
|
385
448
|
}
|
|
386
449
|
|
|
387
450
|
// src/index.ts
|
|
388
|
-
|
|
389
|
-
|
|
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
|
|
390
461
|
var PKG_MANAGERS = ["npm", "yarn", "pnpm", "bun"];
|
|
391
|
-
|
|
392
|
-
|
|
462
|
+
|
|
463
|
+
// src/util/options.ts
|
|
464
|
+
function extractOptions(args) {
|
|
393
465
|
let projectName = "";
|
|
394
|
-
const program = new
|
|
466
|
+
const program = new Command(name);
|
|
395
467
|
program.version(version).option(
|
|
396
468
|
"-t, --template <template>",
|
|
397
469
|
`Choose which template to start from. Valid templates are: ${TEMPLATES.map(
|
|
@@ -403,34 +475,212 @@ async function run() {
|
|
|
403
475
|
).option(
|
|
404
476
|
"-d, --dir <dir>",
|
|
405
477
|
"Choose which directory to run this script from."
|
|
406
|
-
).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) => {
|
|
407
479
|
projectName = name2;
|
|
408
480
|
});
|
|
409
|
-
program.parse(
|
|
481
|
+
program.parse(args);
|
|
410
482
|
const opts = program.opts();
|
|
411
483
|
if (opts.dir) {
|
|
412
484
|
process.chdir(opts.dir);
|
|
413
485
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
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);
|
|
418
668
|
if (!template) {
|
|
419
|
-
|
|
669
|
+
spinner.fail(
|
|
420
670
|
`The provided template '${opts.template}' is invalid. Please provide one of the following: ${TEMPLATES.map(
|
|
421
671
|
(x2) => x2.value
|
|
422
672
|
)}`
|
|
423
673
|
);
|
|
424
|
-
|
|
674
|
+
exit(1);
|
|
425
675
|
}
|
|
426
676
|
}
|
|
427
677
|
let pkgManager = opts.pkgManager;
|
|
428
678
|
if (pkgManager) {
|
|
429
679
|
if (!PKG_MANAGERS.find((_pkgManager) => _pkgManager === pkgManager)) {
|
|
430
|
-
|
|
680
|
+
spinner.fail(
|
|
431
681
|
`The provided package manager '${opts.pkgManager}' is not supported. Please provide one of the following: ${PKG_MANAGERS}`
|
|
432
682
|
);
|
|
433
|
-
|
|
683
|
+
exit(1);
|
|
434
684
|
}
|
|
435
685
|
}
|
|
436
686
|
if (!pkgManager) {
|
|
@@ -441,12 +691,12 @@ async function run() {
|
|
|
441
691
|
}
|
|
442
692
|
}
|
|
443
693
|
if (installedPkgManagers.length === 0) {
|
|
444
|
-
|
|
694
|
+
spinner.fail(
|
|
445
695
|
`You have no supported package managers installed. Please install one of the following: ${PKG_MANAGERS}`
|
|
446
696
|
);
|
|
447
|
-
|
|
697
|
+
exit(1);
|
|
448
698
|
}
|
|
449
|
-
const res = await (
|
|
699
|
+
const res = await prompts({
|
|
450
700
|
message: "Which package manager would you like to use?",
|
|
451
701
|
name: "packageManager",
|
|
452
702
|
type: "select",
|
|
@@ -454,94 +704,151 @@ async function run() {
|
|
|
454
704
|
return { title: manager, value: manager };
|
|
455
705
|
})
|
|
456
706
|
});
|
|
457
|
-
if (!Object.hasOwn(res, "packageManager"))
|
|
707
|
+
if (!Object.hasOwn(res, "packageManager")) exit(1);
|
|
458
708
|
pkgManager = res.packageManager;
|
|
459
709
|
}
|
|
710
|
+
let projectName = opts.projectName;
|
|
460
711
|
if (!projectName) {
|
|
461
|
-
const res = await (
|
|
712
|
+
const res = await prompts({
|
|
462
713
|
name: "name",
|
|
463
714
|
type: "text",
|
|
464
715
|
message: "What is your project named?",
|
|
465
716
|
initial: "my-tina-app",
|
|
466
717
|
validate: (name2) => {
|
|
467
|
-
const {
|
|
468
|
-
|
|
718
|
+
const { message, isError } = validate(
|
|
719
|
+
path4.basename(path4.resolve(name2))
|
|
469
720
|
);
|
|
470
|
-
if (
|
|
471
|
-
return
|
|
721
|
+
if (isError) return `Invalid project name: ${message}`;
|
|
722
|
+
return true;
|
|
472
723
|
}
|
|
473
724
|
});
|
|
474
|
-
if (!Object.hasOwn(res, "name"))
|
|
725
|
+
if (!Object.hasOwn(res, "name")) exit(1);
|
|
475
726
|
projectName = res.name;
|
|
476
727
|
}
|
|
477
728
|
if (!template) {
|
|
478
|
-
const res = await (
|
|
729
|
+
const res = await prompts({
|
|
479
730
|
name: "template",
|
|
480
731
|
type: "select",
|
|
481
732
|
message: "What starter code would you like to use?",
|
|
482
|
-
choices: TEMPLATES
|
|
733
|
+
choices: TEMPLATES.map(formatTemplateChoice)
|
|
483
734
|
});
|
|
484
|
-
if (!Object.hasOwn(res, "template"))
|
|
735
|
+
if (!Object.hasOwn(res, "template")) exit(1);
|
|
485
736
|
template = TEMPLATES.find((_template) => _template.value === res.template);
|
|
486
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
|
+
}
|
|
487
749
|
await telemetry.submitRecord({
|
|
488
750
|
event: {
|
|
489
751
|
name: "create-tina-app:invoke",
|
|
490
|
-
template,
|
|
752
|
+
template: template.value,
|
|
491
753
|
pkgManager
|
|
492
754
|
}
|
|
493
755
|
});
|
|
494
|
-
const rootDir =
|
|
495
|
-
if (!await isWriteable(
|
|
496
|
-
|
|
756
|
+
const rootDir = path4.join(process.cwd(), projectName);
|
|
757
|
+
if (!await isWriteable(path4.dirname(rootDir))) {
|
|
758
|
+
spinner.fail(
|
|
497
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."
|
|
498
760
|
);
|
|
499
761
|
process.exit(1);
|
|
500
762
|
}
|
|
501
|
-
|
|
763
|
+
let appName;
|
|
764
|
+
try {
|
|
765
|
+
appName = await setupProjectDirectory(rootDir);
|
|
766
|
+
} catch (err) {
|
|
767
|
+
spinner.fail(err.message);
|
|
768
|
+
exit(1);
|
|
769
|
+
}
|
|
502
770
|
try {
|
|
503
|
-
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...");
|
|
504
779
|
updateProjectPackageName(rootDir, projectName);
|
|
505
780
|
updateProjectPackageVersion(rootDir, "0.0.1");
|
|
781
|
+
spinner.succeed();
|
|
506
782
|
} catch (err) {
|
|
507
|
-
|
|
508
|
-
|
|
783
|
+
spinner.fail(`Failed to download template: ${err.message}`);
|
|
784
|
+
exit(1);
|
|
509
785
|
}
|
|
510
|
-
|
|
511
|
-
await install(pkgManager);
|
|
512
|
-
log.info("Initializing git repository.");
|
|
786
|
+
spinner.start("Installing packages.");
|
|
513
787
|
try {
|
|
514
|
-
|
|
788
|
+
await install(pkgManager, opts.verbose);
|
|
789
|
+
spinner.succeed();
|
|
790
|
+
} catch (err) {
|
|
791
|
+
spinner.fail(`Failed to install packages: ${err.message}`);
|
|
792
|
+
packageManagerInstallationHadError = true;
|
|
793
|
+
}
|
|
794
|
+
spinner.start("Initializing git repository.");
|
|
795
|
+
try {
|
|
796
|
+
if (initializeGit(spinner)) {
|
|
515
797
|
makeFirstCommit(rootDir);
|
|
516
|
-
|
|
798
|
+
spinner.succeed();
|
|
517
799
|
}
|
|
518
800
|
} catch (err) {
|
|
519
|
-
|
|
801
|
+
spinner.fail("Failed to initialize Git repository, skipping.");
|
|
520
802
|
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
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
|
+
`
|
|
525
811
|
);
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
)
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
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
|
+
);
|
|
542
844
|
}
|
|
543
|
-
run()
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
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);
|
|
547
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 { PackageManager } from '
|
|
1
|
+
import { PackageManager } from './packageManagers';
|
|
2
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,7 +1,7 @@
|
|
|
1
|
-
import { PackageManager } from '
|
|
1
|
+
import { PackageManager } from './packageManagers';
|
|
2
2
|
/**
|
|
3
3
|
* Spawn a package manager installation.
|
|
4
4
|
*
|
|
5
5
|
* @returns A Promise that resolves once the installation is finished.
|
|
6
6
|
*/
|
|
7
|
-
export declare function install(packageManager: PackageManager): Promise<void>;
|
|
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-e1eb9ad-20251211011556",
|
|
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-ddc5e8e-20250611011547"
|
|
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;
|