create-tina-app 0.0.0-e999254-20250610011143 → 0.0.0-f1cec43-20251216232909

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 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 create-tina-app`
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
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- require('../dist')
3
+ import('../dist/index.js');
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
- var index_exports = {};
31
- __export(index_exports, {
32
- run: () => run
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
- var import_fs_extra = __toESM(require("fs-extra"));
46
- var import_path = __toESM(require("path"));
8
+ import fs from "fs-extra";
9
+ import path from "path";
47
10
 
48
- // src/util/logger.ts
49
- var import_chalk = __toESM(require("chalk"));
11
+ // src/util/textstyles.ts
12
+ import chalk from "chalk";
50
13
  var TextStyles = {
51
- link: import_chalk.default.bold.cyan,
52
- cmd: import_chalk.default.inverse,
53
- info: import_chalk.default.blue,
54
- success: import_chalk.default.green,
55
- warn: import_chalk.default.yellow,
56
- err: import_chalk.default.red,
57
- bold: import_chalk.default.bold
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 import_fs_extra.default.promises.access(directory, (import_fs_extra.default.constants || import_fs_extra.default).W_OK);
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 = import_fs_extra.default.readdirSync(root).filter((file) => !validFiles.includes(file)).filter((file) => !/\.iml$/.test(file));
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 = import_path.default.basename(dir);
119
- await import_fs_extra.default.mkdirp(dir);
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
- log.err(
124
- `The directory '${TextStyles.bold(
125
- appName
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 = import_fs_extra.default.lstatSync(import_path.default.join(dir, file));
68
+ const stats = fs.lstatSync(path.join(dir, file));
131
69
  if (stats.isDirectory()) {
132
- log.log(`- ${TextStyles.info(file)}/`);
70
+ errorMessageLines.push(` - ${TextStyles.info(file)}/`);
133
71
  } else {
134
- log.log(`- ${file}`);
72
+ errorMessageLines.push(` - ${file}`);
135
73
  }
136
74
  } catch {
137
- log.log(`- ${file}`);
75
+ errorMessageLines.push(` - ${file}`);
138
76
  }
139
77
  }
140
- process.exit(1);
78
+ throw new Error(errorMessageLines.join("\n"));
141
79
  }
142
80
  return appName;
143
81
  }
144
82
  function updateProjectPackageName(dir, name2) {
145
- const packageJsonPath = import_path.default.join(dir, "package.json");
146
- const packageJson = JSON.parse(import_fs_extra.default.readFileSync(packageJsonPath, "utf8"));
83
+ const packageJsonPath = path.join(dir, "package.json");
84
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
147
85
  packageJson.name = name2;
148
- import_fs_extra.default.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
86
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
149
87
  }
150
88
  function updateProjectPackageVersion(dir, version2) {
151
- const packageJsonPath = import_path.default.join(dir, "package.json");
152
- const packageJson = JSON.parse(import_fs_extra.default.readFileSync(packageJsonPath, "utf8"));
89
+ const packageJsonPath = path.join(dir, "package.json");
90
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
153
91
  packageJson.version = version2;
154
- import_fs_extra.default.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
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
- var import_cross_spawn = __toESM(require("cross-spawn"));
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 = (0, import_cross_spawn.default)(packageManager, ["install"], {
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
- var import_child_process = require("child_process");
177
- var import_path2 = __toESM(require("path"));
178
- var import_fs_extra2 = __toESM(require("fs-extra"));
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
- (0, import_child_process.execSync)("git rev-parse --is-inside-work-tree", { stdio: "ignore" });
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
- (0, import_child_process.execSync)("hg --cwd . root", { stdio: "ignore" });
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
- (0, import_child_process.execSync)("git checkout -b main", { stdio: "ignore" });
198
- (0, import_child_process.execSync)("git add -A", { stdio: "ignore" });
199
- (0, import_child_process.execSync)('git commit -m "Initial commit from Create Tina App"', {
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
- import_fs_extra2.default.removeSync(import_path2.default.join(root, ".git"));
154
+ fs2.removeSync(path2.join(root, ".git"));
204
155
  throw err;
205
156
  }
206
157
  }
207
- function initializeGit() {
208
- (0, import_child_process.execSync)("git --version", { stdio: "ignore" });
158
+ function initializeGit(spinner) {
159
+ execSync("git --version", { stdio: "ignore" });
209
160
  if (isInGitRepository() || isInMercurialRepository()) {
210
- log.warn("Already in a Git repository, skipping.");
161
+ spinner.warn("Already in a Git repository, skipping.");
211
162
  return false;
212
163
  }
213
- if (!import_fs_extra2.default.existsSync(".gitignore")) {
214
- log.warn("There is no .gitignore file in this repository, creating one...");
215
- import_fs_extra2.default.writeFileSync(
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
- (0, import_child_process.execSync)("git init", { stdio: "ignore" });
178
+ execSync("git init", { stdio: "ignore" });
226
179
  return true;
227
180
  }
228
181
 
229
182
  // src/util/examples.ts
230
- var import_node_stream = require("node:stream");
231
- var import_promises = require("node:stream/promises");
232
- var import_tar = require("tar");
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 import_node_stream.Readable.fromWeb(res.body);
220
+ return Readable.fromWeb(res.body);
268
221
  }
269
222
  async function downloadAndExtractRepo(root, { username, name: name2, branch, filePath }) {
270
- await (0, import_promises.pipeline)(
223
+ await pipeline(
271
224
  await downloadTarStream(
272
225
  `https://codeload.github.com/${username}/${name2}/tar.gz/${branch}`
273
226
  ),
274
- (0, import_tar.x)({
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
- var import_fs_extra3 = require("fs-extra");
286
- var import_path3 = __toESM(require("path"));
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 NextJS \u2013 our top recommendation for a seamless, performant, and versatile web experience.",
291
- value: "tina-cloud-starter",
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
- gitURL: "https://github.com/tinacms/tina-cloud-starter"
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
- gitURL: "https://github.com/tinacms/tina-astro-starter"
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
- gitURL: "https://github.com/tinacms/tina-hugo-starter"
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
- gitURL: "https://github.com/tinacms/tina-remix-starter"
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
- gitURL: "https://github.com/tinacms/tinasaurus"
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
- gitURL: "https://github.com/tinacms/tina-barebones-starter"
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
- log.info(
339
- `Downloading files from repo ${TextStyles.link(
340
- `${repoInfo?.username}/${repoInfo?.name}`
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 = import_path3.default.join(__dirname, "..", "examples", template.value);
346
- await (0, import_fs_extra3.copy)(`${templateFile}/`, "./");
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: 18, latest: 22 };
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
- checkSupportedNodeVersion();
360
- }
361
- function checkSupportedNodeVersion() {
421
+ function preRunChecks(spinner) {
422
+ spinner.start("Running pre-run checks...");
362
423
  if (!isSupported) {
363
- log.warn(
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
- var import_child_process2 = require("child_process");
433
+ import { exec } from "child_process";
371
434
  async function checkPackageExists(name2) {
372
435
  try {
373
436
  await new Promise((resolve, reject) => {
374
- (0, import_child_process2.exec)(`${name2} -v`, (error, stdout, stderr) => {
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
- var import_node_process = require("node:process");
389
- var import_validate_npm_package_name = __toESM(require("validate-npm-package-name"));
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
- async function run() {
392
- preRunChecks();
462
+
463
+ // src/util/options.ts
464
+ function extractOptions(args) {
393
465
  let projectName = "";
394
- const program = new import_commander.Command(name);
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(process.argv);
481
+ program.parse(args);
410
482
  const opts = program.opts();
411
483
  if (opts.dir) {
412
484
  process.chdir(opts.dir);
413
485
  }
414
- const telemetry = new import_metrics.Telemetry({ disabled: opts?.noTelemetry });
415
- let template = opts.template;
416
- if (template) {
417
- template = TEMPLATES.find((_template) => _template.value === template);
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
- log.err(
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
- (0, import_node_process.exit)(1);
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
- log.err(
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
- (0, import_node_process.exit)(1);
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
- log.err(
694
+ spinner.fail(
445
695
  `You have no supported package managers installed. Please install one of the following: ${PKG_MANAGERS}`
446
696
  );
447
- (0, import_node_process.exit)(1);
697
+ exit(1);
448
698
  }
449
- const res = await (0, import_prompts.default)({
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")) (0, import_node_process.exit)(1);
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 (0, import_prompts.default)({
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 { validForNewPackages, errors } = (0, import_validate_npm_package_name.default)(
468
- import_node_path.default.basename(import_node_path.default.resolve(name2))
718
+ const { message, isError } = validate(
719
+ path4.basename(path4.resolve(name2))
469
720
  );
470
- if (validForNewPackages) return true;
471
- return `Invalid project name: ${errors[0]}`;
721
+ if (isError) return `Invalid project name: ${message}`;
722
+ return true;
472
723
  }
473
724
  });
474
- if (!Object.hasOwn(res, "name")) (0, import_node_process.exit)(1);
725
+ if (!Object.hasOwn(res, "name")) exit(1);
475
726
  projectName = res.name;
476
727
  }
477
728
  if (!template) {
478
- const res = await (0, import_prompts.default)({
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")) (0, import_node_process.exit)(1);
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 = import_node_path.default.join(process.cwd(), projectName);
495
- if (!await isWriteable(import_node_path.default.dirname(rootDir))) {
496
- log.err(
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
- const appName = await setupProjectDirectory(rootDir);
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
- log.err(`Failed to download template: ${err.message}`);
508
- (0, import_node_process.exit)(1);
783
+ spinner.fail(`Failed to download template: ${err.message}`);
784
+ exit(1);
509
785
  }
510
- log.info("Installing packages.");
511
- await install(pkgManager);
512
- log.info("Initializing git repository.");
786
+ spinner.start("Installing packages.");
513
787
  try {
514
- if (initializeGit()) {
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
- log.info("Initialized git repository.");
798
+ spinner.succeed();
517
799
  }
518
800
  } catch (err) {
519
- log.err("Failed to initialize Git repository, skipping.");
801
+ spinner.fail("Failed to initialize Git repository, skipping.");
520
802
  }
521
- log.success("Starter successfully created!");
522
- if (template.value === "tina-hugo-starter")
523
- log.warn(
524
- `Hugo is required for this starter. Install it via ${TextStyles.link("https://gohugo.io/installation/")}.`
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
- log.log(TextStyles.bold("\nTo launch your app, run:\n"));
527
- log.cmd(`cd ${appName}
528
- ${pkgManager} run dev`);
529
- log.log(`
530
- Next steps:
531
- \u2022 \u{1F4DD} Edit some content on ${TextStyles.link(
532
- "http://localhost:3000"
533
- )} (See ${TextStyles.link("https://tina.io/docs/using-tina-editor")})
534
- \u2022 \u{1F4D6} Learn the basics: ${TextStyles.link("https://tina.io/docs/schema/")}
535
- \u2022 \u{1F58C}\uFE0F Extend Tina with custom field components: ${TextStyles.link(
536
- "https://tina.io/docs/advanced/extending-tina/"
537
- )}
538
- \u2022 \u{1F680} Deploy to Production: ${TextStyles.link(
539
- "https://tina.io/docs/tina-cloud/"
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
- // Annotate the CommonJS export names for ESM import in node:
545
- 0 && (module.exports = {
546
- run
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
+ };
@@ -1,7 +1,14 @@
1
- type BaseExample = {
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 {};
@@ -0,0 +1,7 @@
1
+ type TinaDocsTheme = {
2
+ title: string;
3
+ value: string;
4
+ description: string;
5
+ };
6
+ export declare const THEMES: TinaDocsTheme[];
7
+ export {};
@@ -0,0 +1,3 @@
1
+ export declare const llama: string;
2
+ export declare const errorArt: string;
3
+ export declare const tinaCms: string;
@@ -1,2 +1,2 @@
1
- import { PackageManager } from '..';
1
+ import { PackageManager } from './packageManagers';
2
2
  export declare function checkPackageExists(name: PackageManager): Promise<boolean>;
@@ -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>;
@@ -1,2 +1,3 @@
1
+ import { Ora } from 'ora';
1
2
  export declare function makeFirstCommit(root: string): void;
2
- export declare function initializeGit(): boolean;
3
+ export declare function initializeGit(spinner: Ora): boolean;
@@ -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,9 @@
1
+ export interface CreateOptions {
2
+ template: string;
3
+ pkgManager: string;
4
+ dir: string;
5
+ noTelemetry: boolean;
6
+ projectName: string;
7
+ verbose: boolean;
8
+ }
9
+ export declare function extractOptions(args: string[]): CreateOptions;
@@ -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
- export declare function preRunChecks(): void;
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-e999254-20250610011143",
3
+ "version": "0.0.0-f1cec43-20251216232909",
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": "0.0.0-e999254-20250610011143"
39
+ "@tinacms/scripts": "1.4.2"
39
40
  },
40
41
  "dependencies": {
41
- "chalk": "4.1.2",
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
- "validate-npm-package-name": "^5.0.1",
48
- "@tinacms/metrics": "0.0.0-e999254-20250610011143"
49
+ "@tinacms/metrics": "2.0.1"
49
50
  },
50
51
  "scripts": {
51
52
  "types": "pnpm tsc",
@@ -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;