create-contentisland 0.0.6 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +312 -237
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import { cac as ae } from "cac";
2
- import b from "prompts";
3
- import { existsSync as w } from "node:fs";
4
- import g from "node:fs/promises";
5
- import d from "node:path";
2
+ import S from "prompts";
3
+ import c from "node:fs/promises";
4
+ import l from "node:path";
5
+ import z from "node:child_process";
6
+ import { existsSync as h } from "node:fs";
6
7
  import { createClient as oe } from "@content-island/api-client";
7
- const E = ".content-island", G = "config.json", N = ".gitignore", M = {
8
+ const x = ".content-island", G = "config.json", L = ".gitignore", B = ".env", O = {
8
9
  aa: "Afaraf",
9
10
  ab: "Аҧсуа",
10
11
  ae: "Avesta",
@@ -189,7 +190,7 @@ const E = ".content-island", G = "config.json", N = ".gitignore", M = {
189
190
  za: "Zhuang",
190
191
  zh: "中文",
191
192
  zu: "isiZulu"
192
- }, m = {
193
+ }, p = {
193
194
  reset: "\x1B[0m",
194
195
  green: "\x1B[32m",
195
196
  red: "\x1B[31m",
@@ -199,153 +200,216 @@ const E = ".content-island", G = "config.json", N = ".gitignore", M = {
199
200
  magenta: "\x1B[35m"
200
201
  }, C = (e) => {
201
202
  let t = "";
202
- return e?.bold && (t += m.bold), t;
203
- }, c = {
204
- green: (e, t) => `${m.green}${C(t)}${e}${m.reset}`,
205
- red: (e, t) => `${m.red}${C(t)}${e}${m.reset}`,
206
- yellow: (e, t) => `${m.yellow}${C(t)}${e}${m.reset}`,
207
- bold: (e) => `${m.bold}${e}${m.reset}`,
208
- cyan: (e, t) => `${m.cyan}${C(t)}${e}${m.reset}`,
209
- magenta: (e, t) => `${m.magenta}${C(t)}${e}${m.reset}`
203
+ return e?.bold && (t += p.bold), t;
204
+ }, g = {
205
+ green: (e, t) => `${p.green}${C(t)}${e}${p.reset}`,
206
+ red: (e, t) => `${p.red}${C(t)}${e}${p.reset}`,
207
+ yellow: (e, t) => `${p.yellow}${C(t)}${e}${p.reset}`,
208
+ bold: (e) => `${p.bold}${e}${p.reset}`,
209
+ cyan: (e, t) => `${p.cyan}${C(t)}${e}${p.reset}`,
210
+ magenta: (e, t) => `${p.magenta}${C(t)}${e}${p.reset}`
210
211
  }, o = {
211
- info: (e) => console.log(c.cyan("ℹ️ " + e)),
212
- success: (e) => console.log(c.green("✅ " + e)),
213
- warning: (e) => console.log(c.yellow("⚠️ " + e)),
214
- error: (e) => console.log(c.red("❌ " + e)),
215
- step: (e) => console.log(c.cyan("➡️ " + e)),
212
+ info: (e) => console.log(g.cyan("ℹ️ " + e)),
213
+ success: (e) => console.log(g.green("✅ " + e)),
214
+ warning: (e) => console.log(g.yellow("⚠️ " + e)),
215
+ error: (e) => console.log(g.red("❌ " + e)),
216
+ step: (e) => console.log(g.cyan("➡️ " + e)),
216
217
  title: (e) => console.log(`
217
- ` + c.magenta("🏝️ " + e, { bold: !0 }) + `
218
+ ` + g.magenta("🏝️ " + e, { bold: !0 }) + `
218
219
  `),
219
220
  newLine: () => console.log(""),
220
- token: (e) => console.log(c.green("🔑 " + e)),
221
- language: (e) => console.log(c.magenta(`🌍 Language: ${e}`, { bold: !0 })),
222
- docs: (e) => console.log(c.green("📚 " + e)),
223
- config: (e) => console.log(c.cyan("⚙️ " + e)),
224
- detected: (e) => console.log(c.yellow(`🎯 ${e}`, { bold: !0 })),
225
- loading: (e) => console.log(c.cyan("⏳ " + e)),
226
- complete: (e) => console.log(c.green(`🎉 ${e}`, { bold: !0 })),
227
- created: (e) => console.log(c.green("📁 " + e)),
228
- saved: (e) => console.log(c.cyan("💾 " + e)),
229
- connecting: (e) => console.log(c.cyan("🔗 " + e)),
230
- fetching: (e) => console.log(c.cyan("📥 " + e)),
231
- clearing: (e) => console.log(c.yellow("🧹 " + e)),
232
- updating: (e) => console.log(c.green("🔄 " + e))
233
- }, A = () => d.join(process.cwd(), E), se = async () => {
234
- const e = process.cwd(), t = d.join(e, N), n = `${E}/`;
221
+ token: (e) => console.log(g.green("🔑 " + e)),
222
+ language: (e) => console.log(g.magenta(`🌍 Language: ${e}`, { bold: !0 })),
223
+ docs: (e) => console.log(g.green("📚 " + e)),
224
+ config: (e) => console.log(g.cyan("⚙️ " + e)),
225
+ detected: (e) => console.log(g.yellow(`🎯 ${e}`, { bold: !0 })),
226
+ loading: (e) => console.log(g.cyan("⏳ " + e)),
227
+ complete: (e) => console.log(g.green(`🎉 ${e}`, { bold: !0 })),
228
+ created: (e) => console.log(g.green("📁 " + e)),
229
+ saved: (e) => console.log(g.cyan("💾 " + e)),
230
+ connecting: (e) => console.log(g.cyan("🔗 " + e)),
231
+ fetching: (e) => console.log(g.cyan("📥 " + e)),
232
+ clearing: (e) => console.log(g.yellow("🧹 " + e)),
233
+ updating: (e) => console.log(g.green("🔄 " + e)),
234
+ run: (e) => console.log(g.green("🚀 " + e)),
235
+ command: (e) => console.log(" " + g.magenta(e, { bold: !0 }))
236
+ }, j = () => l.join(process.cwd(), x), se = async () => {
237
+ const e = process.cwd(), t = l.join(e, L), n = `${x}/`;
235
238
  let a = "";
236
- w(t) && (a = await g.readFile(t, "utf-8"), a.includes(n)) || (a = a + `${a.endsWith(`
239
+ h(t) && (a = await c.readFile(t, "utf-8"), a.includes(n)) || (a = a + `${a.endsWith(`
237
240
  `) ? "" : `
238
241
  `}${n}
239
- `, await g.writeFile(t, a, "utf-8"), o.saved(`Added ${n} to ${N}`));
240
- }, K = async () => {
241
- const e = A();
242
+ `, await c.writeFile(t, a, "utf-8"), o.saved(`Added ${n} to ${L}`));
243
+ }, ie = async () => {
244
+ const e = j();
242
245
  try {
243
- w(e) || (await g.mkdir(e, { recursive: !0 }), o.created(`Created: ${E}/`)), await se();
246
+ h(e) || (await c.mkdir(e, { recursive: !0 }), o.created(`Created: ${x}/`)), await se();
244
247
  } catch (t) {
245
248
  o.error(`Failed to create config directory: ${t.message}`);
246
249
  }
247
- }, J = async () => (await K(), d.join(A(), G)), j = async () => {
248
- const e = await J();
249
- if (!w(e))
250
+ }, K = async () => l.join(j(), G), F = async () => {
251
+ const e = await K();
252
+ if (!h(e))
250
253
  return null;
251
254
  try {
252
- const t = await g.readFile(e, "utf-8");
255
+ const t = await c.readFile(e, "utf-8");
253
256
  return JSON.parse(t);
254
257
  } catch (t) {
255
258
  return o.warning(`Could not parse ${G}: ${t.message}`), null;
256
259
  }
257
- }, S = async (e) => {
260
+ }, E = async (e) => {
258
261
  let t = {
259
262
  ...e
260
263
  };
261
- const n = await J();
262
- if (w(n)) {
263
- const a = await j();
264
+ await ie();
265
+ const n = await K();
266
+ if (h(n)) {
267
+ const a = await F();
264
268
  a && (t = { ...a, ...e });
265
269
  }
266
270
  try {
267
271
  const a = JSON.stringify(t, null, 2);
268
- await g.writeFile(n, a, "utf-8"), o.saved(`Saved configuration to ${n}`);
272
+ await c.writeFile(n, a, "utf-8"), o.saved(`Saved configuration to ${n}`);
269
273
  } catch (a) {
270
274
  o.error(`Failed to save configuration: ${a.message}`);
271
275
  }
272
- }, ie = (e, t, n, a) => {
273
- let s = 0, i = t, r = !1, u = "", l = !1;
276
+ }, re = (e, t, n, a) => {
277
+ let s = 0, i = t, r = !1, f = "", u = !1;
274
278
  const y = ['"', "'", "`"].includes(n);
275
- for (let p = t; p < e.length; p++) {
276
- const f = e[p];
277
- if (l) {
278
- l = !1;
279
+ for (let m = t; m < e.length; m++) {
280
+ const d = e[m];
281
+ if (u) {
282
+ u = !1;
279
283
  continue;
280
284
  }
281
- if (f === "\\" && r) {
282
- l = !0;
285
+ if (d === "\\" && r) {
286
+ u = !0;
283
287
  continue;
284
288
  }
285
289
  if (y) {
286
- if (f === n && !r) {
290
+ if (d === n && !r) {
287
291
  if (s++, s === 1)
288
292
  continue;
289
293
  if (s === 2) {
290
- i = p + 1;
294
+ i = m + 1;
291
295
  break;
292
296
  }
293
297
  }
294
- } else if (!r && (f === '"' || f === "'" || f === "`"))
295
- r = !0, u = f;
296
- else if (r && f === u)
298
+ } else if (!r && (d === '"' || d === "'" || d === "`"))
299
+ r = !0, f = d;
300
+ else if (r && d === f)
297
301
  r = !1;
298
302
  else if (!r) {
299
- if (f === n)
303
+ if (d === n)
300
304
  s++;
301
- else if (f === a && (s--, s === 0)) {
302
- i = p + 1;
305
+ else if (d === a && (s--, s === 0)) {
306
+ i = m + 1;
303
307
  break;
304
308
  }
305
309
  }
306
310
  }
307
311
  return i;
308
- }, x = async (e) => {
309
- const { filePath: t, property: n, startSymbol: a, endSymbol: s } = e, i = await g.readFile(t, "utf-8");
312
+ }, I = async (e) => {
313
+ const { filePath: t, property: n, startSymbol: a, endSymbol: s } = e, i = await c.readFile(t, "utf-8");
310
314
  let r = a;
311
315
  a === "[" && (r = "\\["), a === "{" && (r = "\\{"), a === "(" && (r = "\\(");
312
- const u = new RegExp(`${n}\\s*:\\s*(${r})`), l = i.match(u);
313
- if (!l)
316
+ const f = new RegExp(`${n}\\s*:\\s*(${r})`), u = i.match(f);
317
+ if (!u)
314
318
  return null;
315
- const y = i.indexOf(l[0]) + l[0].length - 1, p = ie(i, y, a, s);
316
- return i.substring(y, p);
317
- }, re = (e) => JSON.parse(
319
+ const y = i.indexOf(u[0]) + u[0].length - 1, m = re(i, y, a, s);
320
+ return i.substring(y, m);
321
+ }, ce = (e) => JSON.parse(
318
322
  e.replace(/'/g, '"').replace(/(\w+):/g, '"$1":').replace(/,\s*}/g, "}").replace(/,\s*]/g, "]")
319
- ), q = (e) => e.replace(/"/g, "'").replace(/'(\w+)':/g, "$1:"), ce = async (e, t, n, a) => {
320
- let s = await x(n);
321
- if (s || (s = await x(a)), !s)
323
+ ), q = (e) => e.replace(/"/g, "'").replace(/'(\w+)':/g, "$1:"), le = async (e, t, n, a) => {
324
+ let s = await I(n);
325
+ if (s || (s = await I(a)), !s)
322
326
  throw new Error(
323
327
  `Could not find property '${n.property}' or fallback property '${a.property}' in file ${n.filePath}`
324
328
  );
325
329
  const i = q(JSON.stringify(t, null, 2));
326
- return (await g.readFile(n.filePath, "utf-8")).replace(s, (u) => `${u},
330
+ return (await c.readFile(n.filePath, "utf-8")).replace(s, (f) => `${f},
327
331
  ${e}: ${i}`);
328
- }, T = (e, t) => Array.isArray(e) ? e.map(t) : [], le = (e, t) => ({
332
+ }, ge = ".git", de = (e, t) => {
333
+ const n = z.spawn("git", ["clone", "--depth=1", e, t], { stdio: "inherit" });
334
+ return new Promise((a, s) => {
335
+ n.on("close", (i) => {
336
+ c.rm(l.join(t, ge), { recursive: !0, force: !0 }).finally(() => {
337
+ i === 0 ? a() : s(new Error("Failed to clone repository. Please make sure the target folder is empty and try again."));
338
+ });
339
+ });
340
+ });
341
+ }, ue = (e) => {
342
+ const t = z.spawn("npm", ["install"], {
343
+ cwd: e,
344
+ stdio: "inherit",
345
+ shell: !0
346
+ });
347
+ return new Promise((n) => {
348
+ t.on("close", (a) => {
349
+ a === 0 || o.error("Failed to install dependencies. Please try running 'npm install' manually."), n();
350
+ });
351
+ });
352
+ }, pe = "https://github.com/content-island/template-personal-static-site.git", fe = "create-dev-env.js", U = ".env-sample", me = async (e) => {
353
+ const t = l.join(e, "package.json"), n = await c.readFile(t, "utf-8"), a = JSON.parse(n);
354
+ if (a.scripts) {
355
+ const { predev: s, ...i } = a.scripts;
356
+ a.scripts = i;
357
+ }
358
+ await c.writeFile(t, JSON.stringify(a, null, 2), "utf-8");
359
+ }, we = async (e) => {
360
+ const t = 'CONTENT_ISLAND_ACCESS_TOKEN=YOUR_TOKEN_HERE # You can find the access token in your project’s "General tab" (https://docs.contentisland.net/ui/project/general/)', n = l.join(e, U);
361
+ await c.writeFile(n, t, "utf-8");
362
+ };
363
+ let w = process.cwd();
364
+ const he = () => ({
365
+ id: "personal-static-site",
366
+ hasToSaveConfig: !1,
367
+ getEnvFilePath: () => l.join(w, B),
368
+ onInit: async () => {
369
+ const { projectPath: e } = await S({
370
+ type: "text",
371
+ name: "projectPath",
372
+ message: "Where should we create your new personal static site project?",
373
+ initial: "./"
374
+ });
375
+ e && (w = l.join(process.cwd(), e), o.loading("Cloning Personal Static Site template repository..."), await de(pe, w), o.success("Personal Static Site template repository cloned."));
376
+ const { installDeps: t } = await S({
377
+ type: "confirm",
378
+ name: "installDeps",
379
+ message: "Do you want to install the dependencies now?",
380
+ initial: !0
381
+ });
382
+ t && (o.loading("Installing dependencies..."), await ue(w), o.success("Dependencies installed."));
383
+ },
384
+ syncProject: async () => {
385
+ o.info("Syncing Personal Static Site project..."), await c.unlink(l.join(w, fe)), await c.unlink(l.join(w, U)), await we(w), await me(w), o.success("Personal Static Site project synced.");
386
+ },
387
+ onFinish: async () => {
388
+ o.run("Now you can start your project by running:"), o.newLine();
389
+ const e = l.relative(process.cwd(), w);
390
+ e && o.command(`cd ${e}`), o.command("npm run dev"), o.newLine();
391
+ }
392
+ }), T = (e, t) => Array.isArray(e) ? e.map(t) : [], ye = (e, t) => ({
329
393
  id: e.id,
330
394
  language: e.language,
331
395
  name: e.name,
332
396
  label: e.label,
333
397
  pages: T(e.pages, (n) => t.find((a) => a.id === n))
334
- }), ge = (e, t) => ({
398
+ }), ke = (e, t) => ({
335
399
  id: e.id,
336
400
  language: e.language,
337
401
  index: e.index,
338
- folders: T(e.folders, (n) => le(n, t))
402
+ folders: T(e.folders, (n) => ye(n, t))
339
403
  });
340
- let v = null;
341
- const de = (e) => {
342
- v = oe({ accessToken: e });
343
- }, F = () => {
344
- if (!v)
404
+ let $ = null;
405
+ const Se = (e) => {
406
+ $ = oe({ accessToken: e });
407
+ }, P = () => {
408
+ if (!$)
345
409
  throw new Error("API client not initialized. Call initializeClient first.");
346
- return v;
347
- }, ue = async () => await F().getProject(), O = async (e) => {
348
- const t = F(), n = await t.getContent({
410
+ return $;
411
+ }, Ce = async () => await P().getProject(), _ = async (e) => {
412
+ const t = P(), n = await t.getContent({
349
413
  contentType: "Root",
350
414
  includeRelatedContent: !0,
351
415
  language: e
@@ -361,10 +425,10 @@ const de = (e) => {
361
425
  });
362
426
  if (!s)
363
427
  throw new Error(`Pages not found for IDs: ${a.join(", ")}`);
364
- return ge(n, s);
365
- }, fe = async () => {
428
+ return ke(n, s);
429
+ }, Ee = async () => {
366
430
  try {
367
- return await F().getContent({
431
+ return await P().getContent({
368
432
  contentType: "Meta"
369
433
  });
370
434
  } catch (e) {
@@ -372,35 +436,35 @@ const de = (e) => {
372
436
  "The Content Island API token is missing or malformed. Verify that you've copied the complete token and that you have sufficient permissions."
373
437
  ) : o.error("The requested template is not of type StarLight, so the meta field could not be found."), process.exit(1);
374
438
  }
375
- }, U = "astro.config.mjs", P = () => d.join(process.cwd(), "src", "content", "docs"), L = () => d.join(process.cwd(), U), me = () => {
376
- const e = [], t = L();
377
- w(t) || e.push(U);
378
- const n = P();
379
- return w(n) || e.push("src/content/docs directory"), {
439
+ }, V = "astro.config.mjs", A = () => l.join(process.cwd(), "src", "content", "docs"), N = () => l.join(process.cwd(), V), be = () => {
440
+ const e = [], t = N();
441
+ h(t) || e.push(V);
442
+ const n = A();
443
+ return h(n) || e.push("src/content/docs directory"), {
380
444
  valid: e.length === 0,
381
445
  missingItems: e
382
446
  };
383
- }, pe = async () => {
384
- const e = P();
385
- if (!w(e)) {
386
- o.info("Content docs directory not found, creating it..."), await g.mkdir(e, { recursive: !0 });
447
+ }, ve = async () => {
448
+ const e = A();
449
+ if (!h(e)) {
450
+ o.info("Content docs directory not found, creating it..."), await c.mkdir(e, { recursive: !0 });
387
451
  return;
388
452
  }
389
- const t = await g.readdir(e);
453
+ const t = await c.readdir(e);
390
454
  for (const n of t) {
391
- const a = d.join(e, n);
392
- await g.rm(a, { recursive: !0, force: !0 });
455
+ const a = l.join(e, n);
456
+ await c.rm(a, { recursive: !0, force: !0 });
393
457
  }
394
- }, h = {
458
+ }, k = {
395
459
  sidebar: { start: "[", end: "]" },
396
460
  locales: { start: "{", end: "}" },
397
461
  title: { start: "'", end: "'" }
398
- }, W = (e, t) => {
462
+ }, Y = (e, t) => {
399
463
  const n = [], a = [];
400
464
  for (const s of t) {
401
465
  const i = e.findIndex((r) => r.label === s.label);
402
466
  if (i >= 0) {
403
- const r = s.items && e[i].items ? W(e[i].items || [], s.items) : s.items;
467
+ const r = s.items && e[i].items ? Y(e[i].items || [], s.items) : s.items;
404
468
  n[i] = {
405
469
  ...e[i],
406
470
  ...s,
@@ -410,112 +474,112 @@ const de = (e) => {
410
474
  a.push(s);
411
475
  }
412
476
  return n.push(...a), n.sort((s, i) => {
413
- const r = t.findIndex((l) => l.label === s.label), u = t.findIndex((l) => l.label === i.label);
414
- return r - u;
477
+ const r = t.findIndex((u) => u.label === s.label), f = t.findIndex((u) => u.label === i.label);
478
+ return r - f;
415
479
  });
416
- }, we = (e, t) => {
480
+ }, Ie = (e, t) => {
417
481
  const n = {
418
- root: { lang: e, label: M[e] }
482
+ root: { lang: e, label: O[e] }
419
483
  };
420
484
  return Array.isArray(t) ? t.reduce(
421
485
  (a, s) => ({
422
486
  ...a,
423
- [s]: { lang: s, label: M[s] }
487
+ [s]: { lang: s, label: O[s] }
424
488
  }),
425
489
  n
426
490
  ) : n;
427
491
  }, D = async (e, t, n) => {
428
- const a = L(), s = await x({
492
+ const a = N(), s = await I({
429
493
  filePath: a,
430
494
  property: t,
431
- startSymbol: h[t]?.start,
432
- endSymbol: h[t]?.end
495
+ startSymbol: k[t]?.start,
496
+ endSymbol: k[t]?.end
433
497
  });
434
498
  let i;
435
499
  if (s) {
436
500
  const r = q(JSON.stringify(e, null, 2));
437
- i = (await g.readFile(a, "utf-8")).replace(s, r);
501
+ i = (await c.readFile(a, "utf-8")).replace(s, r);
438
502
  } else
439
- i = await ce(
503
+ i = await le(
440
504
  t,
441
505
  e,
442
506
  {
443
507
  filePath: a,
444
508
  property: n,
445
- startSymbol: h[n]?.start,
446
- endSymbol: h[n]?.end
509
+ startSymbol: k[n]?.start,
510
+ endSymbol: k[n]?.end
447
511
  },
448
512
  {
449
513
  filePath: a,
450
514
  property: "title",
451
- startSymbol: h.title.start,
452
- endSymbol: h.title.end
515
+ startSymbol: k.title.start,
516
+ endSymbol: k.title.end
453
517
  }
454
518
  );
455
- await g.writeFile(a, i, "utf-8");
456
- }, he = async (e, t, n) => {
519
+ await c.writeFile(a, i, "utf-8");
520
+ }, Te = async (e, t, n) => {
457
521
  try {
458
- let a = await x({
459
- filePath: L(),
522
+ let a = await I({
523
+ filePath: N(),
460
524
  property: "sidebar",
461
- startSymbol: h.sidebar.start,
462
- endSymbol: h.sidebar.end
525
+ startSymbol: k.sidebar.start,
526
+ endSymbol: k.sidebar.end
463
527
  }), s = [];
464
528
  try {
465
- s = a ? re(a) : null;
529
+ s = a ? ce(a) : null;
466
530
  } catch {
467
531
  o.warning("Could not parse existing sidebar in astro.config.mjs. A new sidebar will be created."), s = [];
468
532
  }
469
533
  s || (o.warning("No existing sidebar found in astro.config.mjs. A new sidebar will be created."), s = []);
470
- const i = W(s, e);
534
+ const i = Y(s, e);
471
535
  await D(i, "sidebar", "locales");
472
- const r = we(t, n);
536
+ const r = Ie(t, n);
473
537
  await D(r, "locales", "sidebar");
474
538
  } catch (a) {
475
539
  o.error(`Error reading astro.config.mjs: ${a.message}`), process.exit(1);
476
540
  }
477
- }, ye = (e) => /^---\s*\n([\s\S]*?)\n---\s*\n/.test(e), ke = (e) => d.parse(e).name.replace(/[-_]/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").split(" ").filter((a) => a.length > 0).map((a) => a.charAt(0).toUpperCase() + a.slice(1).toLowerCase()).join(" ");
478
- function Ce(e, t, n) {
479
- if (ye(e))
541
+ }, $e = (e) => /^---\s*\n([\s\S]*?)\n---\s*\n/.test(e), xe = (e) => l.parse(e).name.replace(/[-_]/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").split(" ").filter((a) => a.length > 0).map((a) => a.charAt(0).toUpperCase() + a.slice(1).toLowerCase()).join(" ");
542
+ function je(e, t, n) {
543
+ if ($e(e))
480
544
  return e;
481
- const a = ke(t), s = `---
545
+ const a = xe(t), s = `---
482
546
  title: "${a}"
483
547
  ---
484
548
 
485
549
  `;
486
550
  return o.warning(`Missing frontmatter in ${n}`), o.info(`Added default title: "${a}"`), o.warning("Please update the content in Content Island 🏝️ to include proper frontmatter"), o.newLine(), s + e;
487
551
  }
488
- const $ = async (e, t) => {
489
- const n = P(), a = d.join(n, e), s = Ce(t, e, d.relative(process.cwd(), a)), i = d.dirname(a);
490
- w(i) || await g.mkdir(i, { recursive: !0 }), await g.writeFile(a, s, "utf-8");
491
- }, be = async (e, t) => {
552
+ const v = async (e, t) => {
553
+ const n = A(), a = l.join(n, e), s = je(t, e, l.relative(process.cwd(), a)), i = l.dirname(a);
554
+ h(i) || await c.mkdir(i, { recursive: !0 }), await c.writeFile(a, s, "utf-8");
555
+ }, Fe = async (e, t) => {
492
556
  try {
493
- await $(e.index.filename, e.index.content);
557
+ await v(e.index.filename, e.index.content);
494
558
  for (const n of e.folders)
495
559
  for (const a of n.pages)
496
- await $(d.join(n.name, a.filename), a.content);
560
+ await v(l.join(n.name, a.filename), a.content);
497
561
  for (const n of t) {
498
- await $(d.join(n.language, n.index.filename), n.index.content);
562
+ await v(l.join(n.language, n.index.filename), n.index.content);
499
563
  for (const a of n.folders)
500
564
  for (const s of a.pages)
501
- await $(d.join(n.language, a.name, s.filename), s.content);
565
+ await v(l.join(n.language, a.name, s.filename), s.content);
502
566
  }
503
567
  } catch (n) {
504
568
  o.error(`Error updating docs content: ${n.message}`), process.exit(1);
505
569
  }
506
- }, Se = async (e, t) => {
570
+ }, Pe = async (e, t) => {
507
571
  if (e.length === 1) {
508
572
  const s = e[0];
509
- return o.success(`Single language found: ${s}. Continuing...`), await S({ languageCode: s }), s;
573
+ return o.success(`Single language found: ${s}. Continuing...`), await E({ languageCode: s }), s;
510
574
  }
511
- const n = (await j())?.languageCode;
575
+ const n = (await F())?.languageCode;
512
576
  if (n && !t) {
513
577
  if (e.includes(n))
514
578
  return o.info(`Using saved default language: ${n}`), n;
515
579
  o.warning(`Saved language '${n}' not found in project languages`), o.step("Will ask for new default language and save it");
516
580
  }
517
581
  o.step("Multiple languages found. Please select the default language:");
518
- const a = await b({
582
+ const a = await S({
519
583
  type: "select",
520
584
  name: "language",
521
585
  message: "Select the default language:",
@@ -525,8 +589,8 @@ const $ = async (e, t) => {
525
589
  })),
526
590
  initial: 0
527
591
  });
528
- return a.language || (o.error("Language selection is required to continue."), process.exit(1)), n !== a.language && (await S({ languageCode: a.language }), o.config(`Saving default language '${a.language}' to config`)), a.language;
529
- }, Ie = () => {
592
+ return a.language || (o.error("Language selection is required to continue."), process.exit(1)), n !== a.language && (await E({ languageCode: a.language }), o.config(`Saving default language '${a.language}' to config`)), a.language;
593
+ }, Ae = () => {
530
594
  o.detected(`
531
595
  ⭐ ✨ STARLIGHT PROJECT DETECTED ✨ ⭐
532
596
 
@@ -538,120 +602,125 @@ const $ = async (e, t) => {
538
602
  ✨ ⭐ ✨ ⭐ ✨
539
603
  ⭐ ✨ ⭐ ✨
540
604
  `), o.success("All good! Starlight ⭐ project detected successfully."), o.loading("Launching process..."), o.newLine();
541
- }, $e = (e) => {
605
+ }, Ne = (e) => {
542
606
  o.newLine(), o.error("Starlight ⭐ project not found!"), o.newLine(), o.error("Missing required items:"), e.forEach((t) => {
543
607
  o.error(` • ${t}`);
544
608
  }), o.newLine(), o.error("Please make sure you are in the root directory of a Starlight ⭐ project."), o.warning("A Starlight ⭐ project should have:"), o.warning(" • astro.config.mjs file"), o.warning(" • src/content/docs directory"), o.newLine();
545
- }, V = (e) => {
609
+ }, W = (e) => {
546
610
  const t = e.reduce(
547
611
  (n, a) => ({ ...n, ...a }),
548
612
  {}
549
613
  );
550
614
  return Object.keys(t).length > 0 ? t : void 0;
551
- }, Y = (e) => e.filename.replace(/\.(mdx?|md)$/, ""), _ = (e) => e.label ? e.label.trim() : Y(e), xe = (e, t) => {
552
- const n = Y(e), a = t.trim().toLowerCase();
615
+ }, H = (e) => e.filename.replace(/\.(mdx?|md)$/, ""), M = (e) => e.label ? e.label.trim() : H(e), Le = (e, t) => {
616
+ const n = H(e), a = t.trim().toLowerCase();
553
617
  return n.toLocaleLowerCase() === "index" ? a : `${a}/${n}`;
554
- }, Te = (e, t, n) => {
618
+ }, Oe = (e, t, n) => {
555
619
  e.filename.replace(/\.(mdx?|md)$/, "");
556
- const a = n.filter((s) => s.id === e.id).map((s) => ({ [s.language]: _(s) }));
620
+ const a = n.filter((s) => s.id === e.id).map((s) => ({ [s.language]: M(s) }));
557
621
  return {
558
- label: _(e),
559
- slug: xe(e, t),
560
- translations: V(a)
622
+ label: M(e),
623
+ slug: Le(e, t),
624
+ translations: W(a)
561
625
  };
562
- }, R = (e) => e.label ? e.label.trim() : e.name, ve = (e, t) => {
626
+ }, R = (e) => e.label ? e.label.trim() : e.name, _e = (e, t) => {
563
627
  const n = t.flatMap((i) => i.folders ?? []).filter((i) => i.id === e.id), a = n.flatMap((i) => i.pages ?? []).filter((i) => e.pages.some((r) => r.id === i.id)), s = n.map((i) => ({ [i.language]: R(i) }));
564
628
  return {
565
629
  label: R(e),
566
- translations: V(s),
567
- items: T(e.pages, (i) => Te(i, e.name, a))
630
+ translations: W(s),
631
+ items: T(e.pages, (i) => Oe(i, e.name, a))
568
632
  };
569
- }, Ee = (e, t) => T(e.folders, (n) => ve(n, t)), Ae = () => ({
633
+ }, De = (e, t) => T(e.folders, (n) => _e(n, t)), Me = () => ({
570
634
  id: "starlight",
635
+ hasToSaveConfig: !0,
636
+ getEnvFilePath: () => l.join(j(), B),
637
+ onInit: async (e) => {
638
+ o.step("Checking for Starlight ⭐ project...");
639
+ const { valid: t, missingItems: n } = be();
640
+ if (t || (Ne(n), process.exit(1)), Ae(), e.command === "init") {
641
+ const a = l.join(process.cwd(), "package.json"), s = await c.readFile(a, "utf-8"), i = JSON.parse(s), r = i.scripts || {};
642
+ i.scripts = { ...r, "content-update": "npm create contentisland@latest update" }, await c.writeFile(a, JSON.stringify(i, null, 2), "utf-8");
643
+ }
644
+ },
571
645
  syncProject: async (e) => {
572
646
  const { accessToken: t, askIfMultipleLanguages: n } = e;
573
- o.step("Checking for Starlight ⭐ project...");
574
- const { valid: a, missingItems: s } = me();
575
- a || ($e(s), process.exit(1)), Ie(), o.connecting("Initializing Content Island 🏝️ client..."), de(t);
576
- const i = await fe();
577
- o.success(`Connected to project using template: ${i.template} (version: ${i.version})`), i.template !== "starlight" && (o.warning(
647
+ o.connecting("Initializing Content Island 🏝️ client..."), Se(t);
648
+ const a = await Ee();
649
+ o.success(`Connected to project using template: ${a.template} (version: ${a.version})`), a.template !== "starlight" && (o.warning(
578
650
  "The project you are trying to sync is not using the Starlight ⭐ template. Please make sure you are using the correct template."
579
- ), process.exit(1)), await S({
580
- version: i.version
651
+ ), process.exit(1)), await E({
652
+ version: a.version
581
653
  }), o.fetching("Fetching project information from Content Island 🏝️ ...");
582
- const r = await ue();
583
- o.success(`Project fetched: ${r.name}`);
584
- const u = r.languages.map((k) => k);
585
- o.info(`Languages found (${u.length}): ${u.join(", ")}`);
586
- const l = await Se(u, n);
587
- o.language(l);
588
- const y = u.filter((k) => k !== l), p = await O(l);
589
- let f = [];
590
- for (const k of y) {
591
- const ne = await O(k);
592
- f.push(ne);
654
+ const s = await Ce();
655
+ o.success(`Project fetched: ${s.name}`);
656
+ const i = s.languages.map((d) => d);
657
+ o.info(`Languages found (${i.length}): ${i.join(", ")}`);
658
+ const r = await Pe(i, n);
659
+ o.language(r);
660
+ const f = i.filter((d) => d !== r), u = await _(r);
661
+ let y = [];
662
+ for (const d of f) {
663
+ const ne = await _(d);
664
+ y.push(ne);
593
665
  }
594
- o.clearing("Clearing existing docs content..."), await pe(), o.docs("Existing docs content cleared"), o.updating("Updating docs content with fetched data..."), await be(p, f), o.docs("Docs content updated"), o.config("Generating sidebar configuration...");
595
- const te = Ee(p, f);
596
- await he(te, l, y), o.config("Sidebar configuration updated in astro.config.mjs");
666
+ o.clearing("Clearing existing docs content..."), await ve(), o.docs("Existing docs content cleared"), o.updating("Updating docs content with fetched data..."), await Fe(u, y), o.docs("Docs content updated"), o.config("Generating sidebar configuration...");
667
+ const m = De(u, y);
668
+ await Te(m, r, f), o.config("Sidebar configuration updated in astro.config.mjs");
669
+ },
670
+ onFinish: async () => {
671
+ o.run("Now you can start your project by running:"), o.newLine(), o.command("npm run dev"), o.newLine();
597
672
  }
598
- }), H = {
599
- starlight: Ae
600
- }, je = (e) => {
601
- const t = H[e];
673
+ }), Z = {
674
+ starlight: Me,
675
+ "personal-static-site": he
676
+ }, Re = (e) => {
677
+ const t = Z[e];
602
678
  if (!t)
603
679
  throw new Error(`Template "${e}" not found`);
604
680
  return t();
605
- }, Fe = () => Object.keys(H), Pe = async (e, t) => {
681
+ }, Je = () => Object.keys(Z), ze = async (e, t) => {
606
682
  let n;
607
- return n || (n = (await j())?.templateID), n && t && (o.info(`Existing template found: ${n}`), (await b({
683
+ return n || (n = (await F())?.templateID), n && t && (o.info(`Existing template found: ${n}`), (await S({
608
684
  type: "confirm",
609
685
  name: "useExisting",
610
686
  message: `An existing template (${n}) was found. Do you want to use it?`,
611
687
  initial: !0
612
- }))?.useExisting ? o.success(`Using existing template: ${n}`) : (n = null, o.step("Selecting new template..."))), n || (o.step("Please select a template:"), n = (await b({
688
+ }))?.useExisting ? o.success(`Using existing template: ${n}`) : (n = null, o.step("Selecting new template..."))), n || (o.step("Please select a template:"), n = (await S({
613
689
  type: "select",
614
690
  name: "templateID",
615
691
  message: "Select a template:",
616
692
  choices: e.map((s) => ({ title: s, value: s }))
617
693
  }))?.templateID), n || (o.error("Template is required to continue"), process.exit(1)), n;
618
- }, Z = async (e) => {
694
+ }, X = async (e) => {
619
695
  try {
620
- const { selectedTemplateId: t, askIfExists: n } = e, a = Fe();
696
+ const { selectedTemplateId: t, askIfExists: n } = e, a = Je();
621
697
  let s = a.find((i) => i === t);
622
- return s || (s = await Pe(a, n)), o.detected(`Template selected: ${s}`), je(s);
698
+ return s || (s = await ze(a, n)), o.detected(`Template selected: ${s}`), Re(s);
623
699
  } catch (t) {
624
700
  o.error(`Error configuring template: ${t.message}`), process.exit(1);
625
701
  }
626
- }, z = ".env", X = "CONTENT_ISLAND_ACCESS_TOKEN", Le = async (e) => {
627
- switch (e) {
628
- case "starlight":
629
- return await K(), d.join(A(), z);
630
- default:
631
- return d.join(process.cwd(), z);
632
- }
633
- }, Ne = async (e) => {
634
- if (!w(e))
702
+ }, Q = "CONTENT_ISLAND_ACCESS_TOKEN", Ge = async (e) => {
703
+ if (!h(e))
635
704
  return null;
636
705
  try {
637
- const n = (await g.readFile(e, "utf-8")).match(new RegExp(`${X}=(.+)`));
706
+ const n = (await c.readFile(e, "utf-8")).match(new RegExp(`${Q}=(.+)`));
638
707
  return n ? n[1].trim() : null;
639
708
  } catch {
640
709
  return null;
641
710
  }
642
- }, Q = async (e, t) => {
711
+ }, ee = async (e, t) => {
643
712
  try {
644
- const n = `${X}=${e}
645
- `;
646
- await g.writeFile(t, n, "utf-8"), o.token(`Access token saved to ${t}`);
713
+ const n = `${Q}=${e}
714
+ `, a = l.dirname(t);
715
+ await c.mkdir(a, { recursive: !0 }), await c.writeFile(t, n, "utf-8"), o.token(`Access token saved to ${t}`);
647
716
  } catch (n) {
648
717
  o.error(`Failed to save the access token: ${n.message}`);
649
718
  }
650
- }, B = (e) => {
719
+ }, J = (e) => {
651
720
  e || (o.error("Token is required to continue"), process.exit(1));
652
- }, Me = async (e, t) => {
653
- let n = await Ne(e);
654
- if (n && t && (o.info("Found existing Content Island 🏝️ token"), (await b({
721
+ }, Be = async (e, t) => {
722
+ let n = e ? await Ge(e) : null;
723
+ if (n && t && (o.info("Found existing Content Island 🏝️ token"), (await S({
655
724
  type: "confirm",
656
725
  name: "useExisting",
657
726
  message: "An existing token was found. Do you want to use it?",
@@ -660,62 +729,68 @@ const $ = async (e, t) => {
660
729
  o.success("Using existing Content Island 🏝️ token");
661
730
  else {
662
731
  t || o.warning("No existing token found");
663
- const a = await b({
732
+ const a = await S({
664
733
  type: "password",
665
734
  name: "token",
666
735
  message: "Enter your Content Island 🏝️ API token:",
667
736
  validate: (s) => s.length > 0 ? !0 : "Token is required"
668
737
  });
669
- B(a?.token), n = a?.token, await Q(n, e);
738
+ J(a?.token), n = a?.token, e && await ee(n, e);
670
739
  }
671
- return B(n), n;
672
- }, ee = async (e) => {
673
- const { accessToken: t, templateID: n, askIfExists: a } = e;
740
+ return J(n), n;
741
+ }, te = async (e) => {
742
+ const { accessToken: t, envFilePath: n, askIfExists: a } = e;
674
743
  let s = t;
675
- const i = await Le(n);
676
- return s ? (o.success("Using provided Content Island 🏝️ token"), await Q(s, i)) : s = await Me(i, a), s;
677
- }, Oe = async (e) => {
744
+ return s ? (o.success("Using provided Content Island 🏝️ token"), await ee(s, n)) : s = await Be(n, a), s;
745
+ }, Ke = async (e) => {
678
746
  try {
679
747
  o.title("Content Island Integration"), o.step("Configuring template...");
680
- const t = await Z({ selectedTemplateId: e.template, askIfExists: !0 });
681
- o.step("Saving configuration..."), await S({ templateID: t.id }), o.config("Template configuration saved"), o.step("Configuring access token...");
682
- const n = await ee({
748
+ const t = await X({
749
+ selectedTemplateId: e.template,
750
+ askIfExists: !0
751
+ });
752
+ t.onInit && (o.step("Running template initialization..."), await t.onInit({
753
+ command: "init"
754
+ })), t.hasToSaveConfig && (o.step("Saving configuration..."), await E({ templateID: t.id }), o.config("Template configuration saved")), o.step("Configuring access token...");
755
+ const n = t.getEnvFilePath ? t.getEnvFilePath() : null, a = await te({
683
756
  accessToken: e.token,
684
- templateID: t.id,
757
+ envFilePath: n,
685
758
  askIfExists: !0
686
759
  });
687
- o.token("Access token configured successfully"), o.step("Synchronizing project..."), await t.syncProject({ accessToken: n, askIfMultipleLanguages: !0 }), o.docs("Project synchronized with Content Island"), o.newLine(), o.complete("Content Island 🏝️ integration completed successfully!");
760
+ o.token("Access token configured successfully"), o.step("Synchronizing project..."), await t.syncProject({ accessToken: a, askIfMultipleLanguages: !0 }), o.newLine(), o.complete("Content Island 🏝️ integration completed successfully!"), o.newLine(), t.onFinish && await t.onFinish();
688
761
  } catch (t) {
689
762
  o.newLine(), o.error("Error during Content Island integration:"), o.error(t instanceof Error ? t.message : String(t)), process.exit(1);
690
763
  }
691
- }, De = async () => {
764
+ }, qe = async () => {
692
765
  try {
693
766
  o.title("Content Island Integration"), o.step("Configuring template...");
694
- const e = await Z({ askIfExists: !1 });
695
- o.step("Saving configuration..."), await S({ templateID: e.id }), o.config("Template configuration saved"), o.step("Configuring access token...");
696
- const t = await ee({
697
- templateID: e.id,
767
+ const e = await X({ askIfExists: !1 });
768
+ e.onInit && (o.step("Running template initialization..."), await e.onInit({
769
+ command: "update"
770
+ })), e.hasToSaveConfig && (o.step("Saving configuration..."), await E({ templateID: e.id }), o.config("Template configuration saved")), o.step("Configuring access token...");
771
+ const t = e.getEnvFilePath ? e.getEnvFilePath() : null, n = await te({
772
+ envFilePath: t,
698
773
  askIfExists: !1
699
774
  });
700
- o.token("Access token configured successfully"), o.step("Synchronizing project..."), await e.syncProject({ accessToken: t, askIfMultipleLanguages: !1 }), o.docs("Project synchronized with Content Island"), o.newLine(), o.complete("Content Island 🏝️ integration completed successfully!");
775
+ o.token("Access token configured successfully"), o.step("Synchronizing project..."), await e.syncProject({ accessToken: n, askIfMultipleLanguages: !1 }), o.newLine(), o.complete("Content Island 🏝️ integration completed successfully!"), o.newLine(), e.onFinish && await e.onFinish();
701
776
  } catch (e) {
702
777
  o.newLine(), o.error("Error during Content Island integration:"), o.error(e instanceof Error ? e.message : String(e)), process.exit(1);
703
778
  }
704
- }, _e = "0.0.6", Re = {
705
- version: _e
706
- }, I = ae("create-contentisland");
707
- I.command("", "Initialize and validate a project").example("npm create contentisland").example("npm create contentisland --token <token>").example("npm create contentisland --token <token> --template starlight").option(
779
+ }, Ue = "0.1.0", Ve = {
780
+ version: Ue
781
+ }, b = ae("create-contentisland");
782
+ b.command("", "Initialize and validate a project").example("npm create contentisland").example("npm create contentisland --token <token>").example("npm create contentisland --token <token> --template starlight").option(
708
783
  "--token <token>",
709
784
  "Your Content Island token (you can also set the CONTENT_ISLAND_ACCESS_TOKEN environment variable)",
710
785
  {
711
786
  default: process.env.CONTENT_ISLAND_ACCESS_TOKEN || void 0
712
787
  }
713
788
  ).option("--template <template>", "The template to use: starlight.").action(async (e) => {
714
- await Oe(e);
789
+ await Ke(e);
715
790
  });
716
- I.command("update", "Update content from Content Island 🏝️ (preserves existing token)").example("npm create contentisland update").action(async () => {
717
- await De();
791
+ b.command("update", "Update content from Content Island 🏝️ (preserves existing token)").example("npm create contentisland update").action(async () => {
792
+ await qe();
718
793
  });
719
- I.help();
720
- I.version(Re.version);
721
- I.parse();
794
+ b.help();
795
+ b.version(Ve.version);
796
+ b.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-contentisland",
3
- "version": "0.0.6",
3
+ "version": "0.1.0",
4
4
  "description": "Content Island - Starlight CLI",
5
5
  "private": false,
6
6
  "sideEffects": false,
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "type": "module",
17
17
  "imports": {
18
- "#**": "./src/*"
18
+ "#*": "./src/*"
19
19
  },
20
20
  "scripts": {
21
21
  "start:console-runners": "run-p type-check:watch console-runners",