create-tina-app 0.0.0-ec43c87-20250804021103 → 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.
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- require('../dist')
3
+ import('../dist/index.js');
package/dist/index.js CHANGED
@@ -1,127 +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 __commonJS = (cb, mod) => function __require() {
8
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
- };
10
- var __export = (target, all) => {
11
- for (var name2 in all)
12
- __defProp(target, name2, { get: all[name2], enumerable: true });
13
- };
14
- var __copyProps = (to, from, except, desc) => {
15
- if (from && typeof from === "object" || typeof from === "function") {
16
- for (let key of __getOwnPropNames(from))
17
- if (!__hasOwnProp.call(to, key) && key !== except)
18
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
19
- }
20
- return to;
21
- };
22
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
23
- // If the importer is in node compatibility mode or this is not an ESM
24
- // file that has been converted to a CommonJS file using a Babel-
25
- // compatible transform (i.e. "__esModule" has not been set), then set
26
- // "default" to the CommonJS "module.exports" for node compatibility.
27
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
28
- mod
29
- ));
30
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
31
-
32
- // package.json
33
- var require_package = __commonJS({
34
- "package.json"(exports2, module2) {
35
- module2.exports = {
36
- name: "create-tina-app",
37
- version: "1.4.0",
38
- main: "dist/index.js",
39
- files: [
40
- "dist",
41
- "examples",
42
- "bin/*"
43
- ],
44
- bin: "bin/create-tina-app",
45
- typings: "dist/index.d.ts",
46
- license: "Apache-2.0",
47
- buildConfig: {
48
- entryPoints: [
49
- {
50
- name: "src/index.ts",
51
- target: "node"
52
- }
53
- ]
54
- },
55
- engines: {
56
- node: ">=18.18.0"
57
- },
58
- scripts: {
59
- types: "pnpm tsc",
60
- build: "tinacms-scripts build",
61
- "test-run-bin": "pnpm create-tina-app"
62
- },
63
- publishConfig: {
64
- registry: "https://registry.npmjs.org"
65
- },
66
- repository: {
67
- url: "https://github.com/tinacms/tinacms.git",
68
- directory: "packages/create-tina-app"
69
- },
70
- devDependencies: {
71
- "@tinacms/scripts": "workspace:*",
72
- "@types/cross-spawn": "catalog:",
73
- "@types/fs-extra": "^11.0.4",
74
- "@types/node": "^22.13.1",
75
- "@types/prompts": "catalog:",
76
- "@types/tar": "catalog:",
77
- typescript: "^5.7.3"
78
- },
79
- dependencies: {
80
- "@tinacms/metrics": "workspace:*",
81
- chalk: "4.1.2",
82
- commander: "^12.1.0",
83
- "cross-spawn": "catalog:",
84
- "fs-extra": "catalog:",
85
- ora: "^8.2.0",
86
- prompts: "catalog:",
87
- tar: "catalog:",
88
- "validate-npm-package-name": "catalog:"
89
- }
90
- };
91
- }
92
- });
93
-
94
1
  // src/index.ts
95
- var index_exports = {};
96
- __export(index_exports, {
97
- run: () => run
98
- });
99
- module.exports = __toCommonJS(index_exports);
100
- var import_metrics = require("@tinacms/metrics");
101
- var import_prompts = __toESM(require("prompts"));
102
- var import_node_path = __toESM(require("node:path"));
2
+ import { Telemetry } from "@tinacms/metrics";
3
+ import prompts from "prompts";
4
+ import path4 from "node:path";
5
+ import { createRequire } from "node:module";
103
6
 
104
7
  // src/util/fileUtil.ts
105
- var import_fs_extra = __toESM(require("fs-extra"));
106
- var import_path = __toESM(require("path"));
8
+ import fs from "fs-extra";
9
+ import path from "path";
107
10
 
108
11
  // src/util/textstyles.ts
109
- var import_chalk = __toESM(require("chalk"));
12
+ import chalk from "chalk";
110
13
  var TextStyles = {
111
- tinaOrange: import_chalk.default.hex("#EC4816"),
112
- link: (url) => `\x1B]8;;${url}\x07${import_chalk.default.cyan.underline(url)}\x1B]8;;\x07`,
113
- cmd: import_chalk.default.bgBlackBright.bold.white,
114
- info: import_chalk.default.blue,
115
- success: import_chalk.default.green,
116
- warn: import_chalk.default.yellow,
117
- err: import_chalk.default.red,
118
- bold: import_chalk.default.bold
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
119
22
  };
120
23
 
121
24
  // src/util/fileUtil.ts
122
25
  async function isWriteable(directory) {
123
26
  try {
124
- 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);
125
28
  return true;
126
29
  } catch (err) {
127
30
  return false;
@@ -148,12 +51,12 @@ function folderContainsInstallConflicts(root) {
148
51
  "yarn-debug.log",
149
52
  "yarn-error.log"
150
53
  ];
151
- 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));
152
55
  return conflicts;
153
56
  }
154
57
  async function setupProjectDirectory(dir) {
155
- const appName = import_path.default.basename(dir);
156
- await import_fs_extra.default.mkdirp(dir);
58
+ const appName = path.basename(dir);
59
+ await fs.mkdirp(dir);
157
60
  process.chdir(dir);
158
61
  const conflicts = folderContainsInstallConflicts(dir);
159
62
  if (conflicts.length > 0) {
@@ -162,7 +65,7 @@ async function setupProjectDirectory(dir) {
162
65
  ];
163
66
  for (const file of conflicts) {
164
67
  try {
165
- const stats = import_fs_extra.default.lstatSync(import_path.default.join(dir, file));
68
+ const stats = fs.lstatSync(path.join(dir, file));
166
69
  if (stats.isDirectory()) {
167
70
  errorMessageLines.push(` - ${TextStyles.info(file)}/`);
168
71
  } else {
@@ -177,23 +80,36 @@ async function setupProjectDirectory(dir) {
177
80
  return appName;
178
81
  }
179
82
  function updateProjectPackageName(dir, name2) {
180
- const packageJsonPath = import_path.default.join(dir, "package.json");
181
- 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"));
182
85
  packageJson.name = name2;
183
- import_fs_extra.default.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
86
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
184
87
  }
185
88
  function updateProjectPackageVersion(dir, version2) {
186
- const packageJsonPath = import_path.default.join(dir, "package.json");
187
- 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"));
188
91
  packageJson.version = version2;
189
- 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));
190
106
  }
191
107
 
192
108
  // src/util/install.ts
193
- var import_cross_spawn = __toESM(require("cross-spawn"));
109
+ import spawn from "cross-spawn";
194
110
  function install(packageManager, verboseOutput) {
195
111
  return new Promise((resolve, reject) => {
196
- const child = (0, import_cross_spawn.default)(packageManager, ["install"], {
112
+ const child = spawn(packageManager, ["install"], {
197
113
  stdio: verboseOutput ? "inherit" : "ignore",
198
114
  env: { ...process.env, ADBLOCK: "1", DISABLE_OPENCOLLECTIVE: "1" }
199
115
  });
@@ -208,12 +124,12 @@ function install(packageManager, verboseOutput) {
208
124
  }
209
125
 
210
126
  // src/util/git.ts
211
- var import_child_process = require("child_process");
212
- var import_path2 = __toESM(require("path"));
213
- 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";
214
130
  function isInGitRepository() {
215
131
  try {
216
- (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" });
217
133
  return true;
218
134
  } catch (_) {
219
135
  }
@@ -221,7 +137,7 @@ function isInGitRepository() {
221
137
  }
222
138
  function isInMercurialRepository() {
223
139
  try {
224
- (0, import_child_process.execSync)("hg --cwd . root", { stdio: "ignore" });
140
+ execSync("hg --cwd . root", { stdio: "ignore" });
225
141
  return true;
226
142
  } catch (_) {
227
143
  }
@@ -229,27 +145,27 @@ function isInMercurialRepository() {
229
145
  }
230
146
  function makeFirstCommit(root) {
231
147
  try {
232
- (0, import_child_process.execSync)("git checkout -b main", { stdio: "ignore" });
233
- (0, import_child_process.execSync)("git add -A", { stdio: "ignore" });
234
- (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"', {
235
151
  stdio: "ignore"
236
152
  });
237
153
  } catch (err) {
238
- import_fs_extra2.default.removeSync(import_path2.default.join(root, ".git"));
154
+ fs2.removeSync(path2.join(root, ".git"));
239
155
  throw err;
240
156
  }
241
157
  }
242
158
  function initializeGit(spinner) {
243
- (0, import_child_process.execSync)("git --version", { stdio: "ignore" });
159
+ execSync("git --version", { stdio: "ignore" });
244
160
  if (isInGitRepository() || isInMercurialRepository()) {
245
161
  spinner.warn("Already in a Git repository, skipping.");
246
162
  return false;
247
163
  }
248
- if (!import_fs_extra2.default.existsSync(".gitignore")) {
164
+ if (!fs2.existsSync(".gitignore")) {
249
165
  spinner.warn(
250
166
  "There is no .gitignore file in this repository, creating one..."
251
167
  );
252
- import_fs_extra2.default.writeFileSync(
168
+ fs2.writeFileSync(
253
169
  ".gitignore",
254
170
  `node_modules
255
171
  .yarn/*
@@ -259,14 +175,14 @@ function initializeGit(spinner) {
259
175
  `
260
176
  );
261
177
  }
262
- (0, import_child_process.execSync)("git init", { stdio: "ignore" });
178
+ execSync("git init", { stdio: "ignore" });
263
179
  return true;
264
180
  }
265
181
 
266
182
  // src/util/examples.ts
267
- var import_node_stream = require("node:stream");
268
- var import_promises = require("node:stream/promises");
269
- var import_tar = require("tar");
183
+ import { Readable } from "node:stream";
184
+ import { pipeline } from "node:stream/promises";
185
+ import { x } from "tar";
270
186
  async function getRepoInfo(url, examplePath) {
271
187
  const [, username, name2, t, _branch, ...file] = url.pathname.split("/");
272
188
  const filePath = examplePath ? examplePath.replace(/^\//, "") : file.join("/");
@@ -301,14 +217,14 @@ async function downloadTarStream(url) {
301
217
  if (!res.body) {
302
218
  throw new Error(`Failed to download: ${url}`);
303
219
  }
304
- return import_node_stream.Readable.fromWeb(res.body);
220
+ return Readable.fromWeb(res.body);
305
221
  }
306
222
  async function downloadAndExtractRepo(root, { username, name: name2, branch, filePath }) {
307
- await (0, import_promises.pipeline)(
223
+ await pipeline(
308
224
  await downloadTarStream(
309
225
  `https://codeload.github.com/${username}/${name2}/tar.gz/${branch}`
310
226
  ),
311
- (0, import_tar.x)({
227
+ x({
312
228
  cwd: root,
313
229
  strip: filePath ? filePath.split("/").length + 1 : 1,
314
230
  filter: (p) => p.startsWith(
@@ -319,15 +235,51 @@ async function downloadAndExtractRepo(root, { username, name: name2, branch, fil
319
235
  }
320
236
 
321
237
  // src/templates.ts
322
- var import_fs_extra3 = require("fs-extra");
323
- var import_path3 = __toESM(require("path"));
238
+ import { copy } from "fs-extra";
239
+ import path3 from "path";
324
240
  var TEMPLATES = [
325
241
  {
326
242
  title: "\u2B50 NextJS starter",
327
- description: "Kickstart your project with NextJS \u2013 our top recommendation for a seamless, performant, and versatile web experience.",
328
- 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",
329
245
  isInternal: false,
330
- 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",
331
283
  devUrl: "http://localhost:3000"
332
284
  },
333
285
  {
@@ -335,6 +287,20 @@ var TEMPLATES = [
335
287
  description: "Get started with Astro - a modern static site generator designed for fast, lightweight, and flexible web projects.",
336
288
  value: "tina-astro-starter",
337
289
  isInternal: false,
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
+ ],
338
304
  gitURL: "https://github.com/tinacms/tina-astro-starter",
339
305
  devUrl: "http://localhost:4321"
340
306
  },
@@ -343,6 +309,20 @@ var TEMPLATES = [
343
309
  description: "With Hugo, you wield the power of lightning-fast site generation, crafting web experiences at the speed of thought.",
344
310
  value: "tina-hugo-starter",
345
311
  isInternal: false,
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
+ ],
346
326
  gitURL: "https://github.com/tinacms/tina-hugo-starter",
347
327
  devUrl: "http://localhost:1313"
348
328
  },
@@ -351,6 +331,20 @@ var TEMPLATES = [
351
331
  description: "Dive into Remix to orchestrate seamless, interactive user journeys like a maestro of the web.",
352
332
  value: "tina-remix-starter",
353
333
  isInternal: false,
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
+ ],
354
348
  gitURL: "https://github.com/tinacms/tina-remix-starter",
355
349
  devUrl: "http://localhost:3000"
356
350
  },
@@ -359,14 +353,42 @@ var TEMPLATES = [
359
353
  description: "Docusaurus empowers you to build and evolve documentation like crafting a living, breathing knowledge repository.",
360
354
  value: "tinasaurus",
361
355
  isInternal: false,
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
+ ],
362
370
  gitURL: "https://github.com/tinacms/tinasaurus",
363
371
  devUrl: "http://localhost:3000"
364
372
  },
365
373
  {
366
374
  title: "Bare bones starter",
367
- 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.",
368
376
  value: "basic",
369
377
  isInternal: false,
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
+ ],
370
392
  gitURL: "https://github.com/tinacms/tina-barebones-starter",
371
393
  devUrl: "http://localhost:3000"
372
394
  }
@@ -383,8 +405,8 @@ async function downloadTemplate(template, root, spinner) {
383
405
  )}`;
384
406
  await downloadAndExtractRepo(root, repoInfo);
385
407
  } else {
386
- const templateFile = import_path3.default.join(__dirname, "..", "examples", template.value);
387
- await (0, import_fs_extra3.copy)(`${templateFile}/`, "./");
408
+ const templateFile = path3.join(__dirname, "..", "examples", template.value);
409
+ await copy(`${templateFile}/`, "./");
388
410
  }
389
411
  }
390
412
 
@@ -408,11 +430,11 @@ function preRunChecks(spinner) {
408
430
  }
409
431
 
410
432
  // src/util/checkPkgManagers.ts
411
- var import_child_process2 = require("child_process");
433
+ import { exec } from "child_process";
412
434
  async function checkPackageExists(name2) {
413
435
  try {
414
436
  await new Promise((resolve, reject) => {
415
- (0, import_child_process2.exec)(`${name2} -v`, (error, stdout, stderr) => {
437
+ exec(`${name2} -v`, (error, stdout, stderr) => {
416
438
  if (error) {
417
439
  reject(stderr);
418
440
  }
@@ -426,12 +448,14 @@ async function checkPackageExists(name2) {
426
448
  }
427
449
 
428
450
  // src/index.ts
429
- var import_node_process = require("node:process");
430
- var import_ora = __toESM(require("ora"));
451
+ import { exit } from "node:process";
431
452
 
432
453
  // src/util/options.ts
433
- var import_commander = require("commander");
434
- var import_package = __toESM(require_package());
454
+ import { Command } from "commander";
455
+
456
+ // package.json
457
+ var name = "create-tina-app";
458
+ var version = "2.0.0";
435
459
 
436
460
  // src/util/packageManagers.ts
437
461
  var PKG_MANAGERS = ["npm", "yarn", "pnpm", "bun"];
@@ -439,8 +463,8 @@ var PKG_MANAGERS = ["npm", "yarn", "pnpm", "bun"];
439
463
  // src/util/options.ts
440
464
  function extractOptions(args) {
441
465
  let projectName = "";
442
- const program = new import_commander.Command(import_package.name);
443
- program.version(import_package.version).option(
466
+ const program = new Command(name);
467
+ program.version(version).option(
444
468
  "-t, --template <template>",
445
469
  `Choose which template to start from. Valid templates are: ${TEMPLATES.map(
446
470
  (x2) => x2.value
@@ -465,27 +489,179 @@ function extractOptions(args) {
465
489
  return opts;
466
490
  }
467
491
 
468
- // src/index.ts
469
- var import_validate_npm_package_name = __toESM(require("validate-npm-package-name"));
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
+ }
470
593
 
471
594
  // src/util/asciiArt.ts
472
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 ";
473
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";
474
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
+
475
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
+ }
476
649
  async function run() {
650
+ const ora = (await import("ora")).default;
651
+ let packageManagerInstallationHadError = false;
477
652
  if (process.stdout.columns >= 60) {
478
653
  console.log(TextStyles.tinaOrange(`${llama}`));
479
654
  console.log(TextStyles.tinaOrange(`${tinaCms}`));
480
655
  } else {
481
656
  console.log(TextStyles.tinaOrange(`\u{1F999} TinaCMS`));
482
657
  }
483
- const version2 = require_package().version;
658
+ const require2 = createRequire(import.meta.url);
659
+ const version2 = require2("../package.json").version;
484
660
  console.log(`Create Tina App v${version2}`);
485
- const spinner = (0, import_ora.default)();
661
+ const spinner = ora();
486
662
  preRunChecks(spinner);
487
663
  const opts = extractOptions(process.argv);
488
- const telemetry = new import_metrics.Telemetry({ disabled: opts?.noTelemetry });
664
+ const telemetry = new Telemetry({ disabled: opts?.noTelemetry });
489
665
  let template = null;
490
666
  if (opts.template) {
491
667
  template = TEMPLATES.find((_template) => _template.value === opts.template);
@@ -495,7 +671,7 @@ async function run() {
495
671
  (x2) => x2.value
496
672
  )}`
497
673
  );
498
- (0, import_node_process.exit)(1);
674
+ exit(1);
499
675
  }
500
676
  }
501
677
  let pkgManager = opts.pkgManager;
@@ -504,7 +680,7 @@ async function run() {
504
680
  spinner.fail(
505
681
  `The provided package manager '${opts.pkgManager}' is not supported. Please provide one of the following: ${PKG_MANAGERS}`
506
682
  );
507
- (0, import_node_process.exit)(1);
683
+ exit(1);
508
684
  }
509
685
  }
510
686
  if (!pkgManager) {
@@ -518,9 +694,9 @@ async function run() {
518
694
  spinner.fail(
519
695
  `You have no supported package managers installed. Please install one of the following: ${PKG_MANAGERS}`
520
696
  );
521
- (0, import_node_process.exit)(1);
697
+ exit(1);
522
698
  }
523
- const res = await (0, import_prompts.default)({
699
+ const res = await prompts({
524
700
  message: "Which package manager would you like to use?",
525
701
  name: "packageManager",
526
702
  type: "select",
@@ -528,37 +704,48 @@ async function run() {
528
704
  return { title: manager, value: manager };
529
705
  })
530
706
  });
531
- if (!Object.hasOwn(res, "packageManager")) (0, import_node_process.exit)(1);
707
+ if (!Object.hasOwn(res, "packageManager")) exit(1);
532
708
  pkgManager = res.packageManager;
533
709
  }
534
710
  let projectName = opts.projectName;
535
711
  if (!projectName) {
536
- const res = await (0, import_prompts.default)({
712
+ const res = await prompts({
537
713
  name: "name",
538
714
  type: "text",
539
715
  message: "What is your project named?",
540
716
  initial: "my-tina-app",
541
717
  validate: (name2) => {
542
- const { validForNewPackages, errors } = (0, import_validate_npm_package_name.default)(
543
- import_node_path.default.basename(import_node_path.default.resolve(name2))
718
+ const { message, isError } = validate(
719
+ path4.basename(path4.resolve(name2))
544
720
  );
545
- if (validForNewPackages) return true;
546
- return `Invalid project name: ${errors[0]}`;
721
+ if (isError) return `Invalid project name: ${message}`;
722
+ return true;
547
723
  }
548
724
  });
549
- if (!Object.hasOwn(res, "name")) (0, import_node_process.exit)(1);
725
+ if (!Object.hasOwn(res, "name")) exit(1);
550
726
  projectName = res.name;
551
727
  }
552
728
  if (!template) {
553
- const res = await (0, import_prompts.default)({
729
+ const res = await prompts({
554
730
  name: "template",
555
731
  type: "select",
556
732
  message: "What starter code would you like to use?",
557
- choices: TEMPLATES
733
+ choices: TEMPLATES.map(formatTemplateChoice)
558
734
  });
559
- if (!Object.hasOwn(res, "template")) (0, import_node_process.exit)(1);
735
+ if (!Object.hasOwn(res, "template")) exit(1);
560
736
  template = TEMPLATES.find((_template) => _template.value === res.template);
561
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
+ }
562
749
  await telemetry.submitRecord({
563
750
  event: {
564
751
  name: "create-tina-app:invoke",
@@ -566,8 +753,8 @@ async function run() {
566
753
  pkgManager
567
754
  }
568
755
  });
569
- const rootDir = import_node_path.default.join(process.cwd(), projectName);
570
- if (!await isWriteable(import_node_path.default.dirname(rootDir))) {
756
+ const rootDir = path4.join(process.cwd(), projectName);
757
+ if (!await isWriteable(path4.dirname(rootDir))) {
571
758
  spinner.fail(
572
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."
573
760
  );
@@ -578,9 +765,13 @@ async function run() {
578
765
  appName = await setupProjectDirectory(rootDir);
579
766
  } catch (err) {
580
767
  spinner.fail(err.message);
581
- (0, import_node_process.exit)(1);
768
+ exit(1);
582
769
  }
583
770
  try {
771
+ await downloadTemplate(template, rootDir, spinner);
772
+ if (themeChoice) {
773
+ await updateThemeSettings(rootDir, themeChoice);
774
+ }
584
775
  spinner.start("Downloading template...");
585
776
  await downloadTemplate(template, rootDir, spinner);
586
777
  spinner.succeed();
@@ -590,7 +781,7 @@ async function run() {
590
781
  spinner.succeed();
591
782
  } catch (err) {
592
783
  spinner.fail(`Failed to download template: ${err.message}`);
593
- (0, import_node_process.exit)(1);
784
+ exit(1);
594
785
  }
595
786
  spinner.start("Installing packages.");
596
787
  try {
@@ -598,7 +789,7 @@ async function run() {
598
789
  spinner.succeed();
599
790
  } catch (err) {
600
791
  spinner.fail(`Failed to install packages: ${err.message}`);
601
- (0, import_node_process.exit)(1);
792
+ packageManagerInstallationHadError = true;
602
793
  }
603
794
  spinner.start("Initializing git repository.");
604
795
  try {
@@ -613,33 +804,51 @@ async function run() {
613
804
  `);
614
805
  if (template.value === "tina-hugo-starter") {
615
806
  spinner.warn(
616
- `Hugo is required for this starter. Install it via ${TextStyles.link("https://gohugo.io/installation/")}
807
+ `Hugo is required for this starter. Install it via ${TextStyles.link(
808
+ "https://gohugo.io/installation/"
809
+ )}
617
810
  `
618
811
  );
619
812
  }
620
813
  const padCommand = (cmd, width = 20) => TextStyles.cmd(cmd) + " ".repeat(Math.max(0, width - cmd.length));
621
814
  spinner.info(`${TextStyles.bold("To get started:")}
622
815
 
623
- ${padCommand(`cd ${appName}`)}# move into your project directory
624
- ${padCommand(`${pkgManager} run dev`)}# start the dev server ${TextStyles.link(template.devUrl)}
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)}
625
821
  ${padCommand(`${pkgManager} run build`)}# build the app for production
626
822
  `);
627
823
  console.log("Next steps:");
628
824
  console.log(
629
- ` \u2022 \u{1F4DD} Edit some content: ${TextStyles.link("https://tina.io/docs/using-tina-editor")}`
825
+ ` \u2022 \u{1F4DD} Edit some content: ${TextStyles.link(
826
+ "https://tina.io/docs/using-tina-editor"
827
+ )}`
630
828
  );
631
829
  console.log(
632
- ` \u2022 \u{1F4D6} Learn the basics: ${TextStyles.link("https://tina.io/docs/schema/")}`
830
+ ` \u2022 \u{1F4D6} Learn the basics: ${TextStyles.link(
831
+ "https://tina.io/docs/schema/"
832
+ )}`
633
833
  );
634
834
  console.log(
635
- ` \u2022 \u{1F58C}\uFE0F Extend Tina with custom field components: ${TextStyles.link("https://tina.io/docs/advanced/extending-tina/")}`
835
+ ` \u2022 \u{1F58C}\uFE0F Extend Tina with custom field components: ${TextStyles.link(
836
+ "https://tina.io/docs/advanced/extending-tina/"
837
+ )}`
636
838
  );
637
839
  console.log(
638
- ` \u2022 \u{1F680} Deploy to Production: ${TextStyles.link("https://tina.io/docs/tina-cloud/")}`
840
+ ` \u2022 \u{1F680} Deploy to Production: ${TextStyles.link(
841
+ "https://tina.io/docs/tinacloud/"
842
+ )}`
639
843
  );
640
844
  }
641
- run();
642
- // Annotate the CommonJS export names for ESM import in node:
643
- 0 && (module.exports = {
644
- 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);
645
851
  });
852
+ export {
853
+ run
854
+ };
@@ -1,7 +1,12 @@
1
1
  import { Ora } from 'ora';
2
- type BaseExample = {
2
+ type Feature = {
3
+ name: string;
4
+ description: string;
5
+ };
6
+ export type BaseExample = {
3
7
  title: string;
4
8
  description?: string;
9
+ features?: Feature[];
5
10
  value: string;
6
11
  devUrl: string;
7
12
  };
@@ -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 {};
@@ -1,2 +1,3 @@
1
1
  export declare const llama: string;
2
+ export declare const errorArt: string;
2
3
  export declare const tinaCms: string;
@@ -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>;
@@ -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
+ };
@@ -1,11 +1,10 @@
1
- import chalk from 'chalk';
2
1
  export declare const TextStyles: {
3
- tinaOrange: chalk.Chalk;
2
+ tinaOrange: import("chalk").ChalkInstance;
4
3
  link: (url: string) => string;
5
- cmd: chalk.Chalk;
6
- info: chalk.Chalk;
7
- success: chalk.Chalk;
8
- warn: chalk.Chalk;
9
- err: chalk.Chalk;
10
- bold: chalk.Chalk;
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;
11
10
  };
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "create-tina-app",
3
- "version": "0.0.0-ec43c87-20250804021103",
3
+ "version": "0.0.0-f1cec43-20251216232909",
4
+ "type": "module",
4
5
  "main": "dist/index.js",
5
6
  "files": [
6
7
  "dist",
@@ -35,18 +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": "1.4.0"
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",
45
46
  "ora": "^8.2.0",
46
47
  "prompts": "^2.4.2",
47
48
  "tar": "7.4.0",
48
- "validate-npm-package-name": "^5.0.1",
49
- "@tinacms/metrics": "1.1.0"
49
+ "@tinacms/metrics": "2.0.1"
50
50
  },
51
51
  "scripts": {
52
52
  "types": "pnpm tsc",