create-contentisland 0.0.1

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 (3) hide show
  1. package/cli.js +2 -0
  2. package/dist/index.js +716 -0
  3. package/package.json +37 -0
package/cli.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ await import('./dist/index.js');
package/dist/index.js ADDED
@@ -0,0 +1,716 @@
1
+ import { cac as ae } from "cac";
2
+ import S from "prompts";
3
+ import { existsSync as w } from "node:fs";
4
+ import l from "node:fs/promises";
5
+ import g from "node:path";
6
+ import { createClient as oe } from "@content-island/api-client";
7
+ const x = ".content-island", G = "config.json", N = ".gitignore", M = {
8
+ aa: "Afaraf",
9
+ ab: "Аҧсуа",
10
+ ae: "Avesta",
11
+ af: "Afrikaans",
12
+ ak: "Akan",
13
+ am: "አማርኛ",
14
+ an: "Aragonés",
15
+ ar: "العربية",
16
+ as: "অসমীয়া",
17
+ av: "Авар мацӀ",
18
+ ay: "Aymar aru",
19
+ az: "Azərbaycan",
20
+ ba: "Башҡортса",
21
+ be: "Беларуская",
22
+ bg: "Български",
23
+ bh: "भोजपुरी",
24
+ bi: "Bislama",
25
+ bm: "Bamanankan",
26
+ bn: "বাংলা",
27
+ bo: "བོད་ཡིག",
28
+ br: "Brezhoneg",
29
+ bs: "Bosanski",
30
+ ca: "Català",
31
+ ce: "Нохчийн",
32
+ ch: "Chamoru",
33
+ co: "Corsu",
34
+ cr: "Nehiyaw",
35
+ cs: "Čeština",
36
+ cu: "ѩзыкъ словѣньскъ",
37
+ cv: "Чӑвашла",
38
+ cy: "Cymraeg",
39
+ da: "Dansk",
40
+ de: "Deutsch",
41
+ dv: "ދިވެހި",
42
+ dz: "རྫོང་ཁ",
43
+ ee: "Eʋegbe",
44
+ el: "Ελληνικά",
45
+ en: "English",
46
+ eo: "Esperanto",
47
+ es: "Español",
48
+ et: "Eesti",
49
+ eu: "Euskera",
50
+ fa: "فارسی",
51
+ ff: "Fulfulde",
52
+ fi: "Suomi",
53
+ fj: "Vosa Vakaviti",
54
+ fo: "Føroyskt",
55
+ fr: "Français",
56
+ fy: "Frysk",
57
+ ga: "Gaeilge",
58
+ gd: "Gàidhlig",
59
+ gl: "Galego",
60
+ gn: "Avañe'ẽ",
61
+ gu: "ગુજરાતી",
62
+ gv: "Gaelg",
63
+ ha: "Hausa",
64
+ he: "עברית",
65
+ hi: "हिन्दी",
66
+ ho: "Hiri Motu",
67
+ hr: "Hrvatski",
68
+ ht: "Kreyòl ayisyen",
69
+ hu: "Magyar",
70
+ hy: "Հայերեն",
71
+ hz: "Otjiherero",
72
+ ia: "Interlingua",
73
+ id: "Bahasa Indonesia",
74
+ ie: "Interlingue",
75
+ ig: "Asụsụ Igbo",
76
+ ii: "ꆈꌠ꒿ Nuosuhxop",
77
+ ik: "Iñupiaq",
78
+ io: "Ido",
79
+ is: "Íslenska",
80
+ it: "Italiano",
81
+ iu: "ᐃᓄᒃᑎᑐᑦ",
82
+ ja: "日本語",
83
+ jv: "Basa Jawa",
84
+ ka: "ქართული",
85
+ kg: "Kikongo",
86
+ ki: "Gĩkũyũ",
87
+ kj: "Kuanyama",
88
+ kk: "Қазақша",
89
+ kl: "Kalaallisut",
90
+ km: "ខ្មែរ",
91
+ kn: "ಕನ್ನಡ",
92
+ ko: "한국어",
93
+ kr: "Kanuri",
94
+ ks: "कश्मीरी",
95
+ ku: "Kurdî",
96
+ kv: "Коми кыв",
97
+ kw: "Kernewek",
98
+ ky: "Кыргызча",
99
+ la: "Latina",
100
+ lb: "Lëtzebuergesch",
101
+ lg: "Luganda",
102
+ li: "Limburgs",
103
+ ln: "Lingála",
104
+ lo: "ລາວ",
105
+ lt: "Lietuvių",
106
+ lu: "Tshiluba",
107
+ lv: "Latviešu",
108
+ mg: "Malagasy",
109
+ mh: "Kajin M̧ajeļ",
110
+ mi: "Māori",
111
+ mk: "Македонски",
112
+ ml: "മലയാളം",
113
+ mn: "Монгол",
114
+ mr: "मराठी",
115
+ ms: "Bahasa Melayu",
116
+ mt: "Malti",
117
+ my: "မြန်မာ",
118
+ na: "Dorerin Naoero",
119
+ nb: "Norsk Bokmål",
120
+ nd: "isiNdebele",
121
+ ne: "नेपाली",
122
+ ng: "Oshiwambo",
123
+ nl: "Nederlands",
124
+ nn: "Norsk Nynorsk",
125
+ no: "Norsk",
126
+ nr: "isiNdebele",
127
+ nv: "Diné bizaad",
128
+ ny: "ChiCheŵa",
129
+ oc: "Occitan",
130
+ oj: "ᐊᓂᔑᓈᐯᒧᐎᓐ",
131
+ om: "Afaan Oromoo",
132
+ or: "ଓଡ଼ିଆ",
133
+ os: "Ирон æвзаг",
134
+ pa: "ਪੰਜਾਬੀ",
135
+ pi: "Pāli",
136
+ pl: "Polski",
137
+ ps: "پښتو",
138
+ pt: "Português",
139
+ qu: "Runa Simi",
140
+ rm: "Rumantsch",
141
+ rn: "Ikirundi",
142
+ ro: "Română",
143
+ ru: "Русский",
144
+ rw: "Kinyarwanda",
145
+ sa: "संस्कृतम्",
146
+ sc: "Sardu",
147
+ sd: "सिन्धी",
148
+ se: "Sámegiella",
149
+ sg: "Sängö",
150
+ si: "සිංහල",
151
+ sk: "Slovenčina",
152
+ sl: "Slovenščina",
153
+ sm: "Gagana Samoa",
154
+ sn: "ChiShona",
155
+ so: "Soomaali",
156
+ sq: "Shqip",
157
+ sr: "Српски",
158
+ ss: "SiSwati",
159
+ st: "Sesotho",
160
+ su: "Sundanese",
161
+ sv: "Svenska",
162
+ sw: "Kiswahili",
163
+ ta: "தமிழ்",
164
+ te: "తెలుగు",
165
+ tg: "Тоҷикӣ",
166
+ th: "ไทย",
167
+ ti: "ትግርኛ",
168
+ tk: "Türkmençe",
169
+ tl: "Filipino",
170
+ tn: "Setswana",
171
+ to: "Faka Tonga",
172
+ tr: "Türkçe",
173
+ ts: "Xitsonga",
174
+ tt: "Татарча",
175
+ tw: "Twi",
176
+ ty: "Reo Māʻohi",
177
+ ug: "ئۇيغۇرچە",
178
+ uk: "Українська",
179
+ ur: "اردو",
180
+ uz: "Oʻzbekcha",
181
+ ve: "Tshivenda",
182
+ vi: "Tiếng Việt",
183
+ vo: "Volapük",
184
+ wa: "Walon",
185
+ wo: "Wolof",
186
+ xh: "isiXhosa",
187
+ yi: "ייִדיש",
188
+ yo: "Yorùbá",
189
+ za: "Zhuang",
190
+ zh: "中文",
191
+ zu: "isiZulu"
192
+ }, u = {
193
+ reset: "\x1B[0m",
194
+ green: "\x1B[32m",
195
+ red: "\x1B[31m",
196
+ yellow: "\x1B[33m",
197
+ bold: "\x1B[1m",
198
+ cyan: "\x1B[36m",
199
+ magenta: "\x1B[35m"
200
+ }, C = (e) => {
201
+ let n = "";
202
+ return e?.bold && (n += u.bold), n;
203
+ }, c = {
204
+ green: (e, n) => `${u.green}${C(n)}${e}${u.reset}`,
205
+ red: (e, n) => `${u.red}${C(n)}${e}${u.reset}`,
206
+ yellow: (e, n) => `${u.yellow}${C(n)}${e}${u.reset}`,
207
+ bold: (e) => `${u.bold}${e}${u.reset}`,
208
+ cyan: (e, n) => `${u.cyan}${C(n)}${e}${u.reset}`,
209
+ magenta: (e, n) => `${u.magenta}${C(n)}${e}${u.reset}`
210
+ }, 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)),
216
+ title: (e) => console.log(`
217
+ ` + c.magenta("🏝️ " + e, { bold: !0 }) + `
218
+ `),
219
+ 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 = () => g.join(process.cwd(), x), se = async () => {
234
+ const e = process.cwd(), n = g.join(e, N), t = `${x}/`;
235
+ let a = "";
236
+ w(n) && (a = await l.readFile(n, "utf-8"), a.includes(t)) || (a = a + `${a.endsWith(`
237
+ `) ? "" : `
238
+ `}${t}
239
+ `, await l.writeFile(n, a, "utf-8"), o.saved(`Added ${t} to ${N}`));
240
+ }, K = async () => {
241
+ const e = A();
242
+ try {
243
+ w(e) || (await l.mkdir(e, { recursive: !0 }), o.created(`Created: ${x}/`)), await se();
244
+ } catch (n) {
245
+ o.error(`Failed to create config directory: ${n.message}`);
246
+ }
247
+ }, J = async () => (await K(), g.join(A(), G)), j = async () => {
248
+ const e = await J();
249
+ if (!w(e))
250
+ return null;
251
+ try {
252
+ const n = await l.readFile(e, "utf-8");
253
+ return JSON.parse(n);
254
+ } catch (n) {
255
+ return o.warning(`Could not parse ${G}: ${n.message}`), null;
256
+ }
257
+ }, b = async (e) => {
258
+ let n = {
259
+ ...e
260
+ };
261
+ const t = await J();
262
+ if (w(t)) {
263
+ const a = await j();
264
+ a && (n = { ...a, ...e });
265
+ }
266
+ try {
267
+ const a = JSON.stringify(n, null, 2);
268
+ await l.writeFile(t, a, "utf-8"), o.saved(`Saved configuration to ${t}`);
269
+ } catch (a) {
270
+ o.error(`Failed to save configuration: ${a.message}`);
271
+ }
272
+ }, ie = (e, n, t, a) => {
273
+ let s = 0, i = n, r = !1, f = "", m = !1;
274
+ const y = ['"', "'", "`"].includes(t);
275
+ for (let p = n; p < e.length; p++) {
276
+ const d = e[p];
277
+ if (m) {
278
+ m = !1;
279
+ continue;
280
+ }
281
+ if (d === "\\" && r) {
282
+ m = !0;
283
+ continue;
284
+ }
285
+ if (y) {
286
+ if (d === t && !r) {
287
+ if (s++, s === 1)
288
+ continue;
289
+ if (s === 2) {
290
+ i = p + 1;
291
+ break;
292
+ }
293
+ }
294
+ } else if (!r && (d === '"' || d === "'" || d === "`"))
295
+ r = !0, f = d;
296
+ else if (r && d === f)
297
+ r = !1;
298
+ else if (!r) {
299
+ if (d === t)
300
+ s++;
301
+ else if (d === a && (s--, s === 0)) {
302
+ i = p + 1;
303
+ break;
304
+ }
305
+ }
306
+ }
307
+ return i;
308
+ }, E = async (e) => {
309
+ const { filePath: n, property: t, startSymbol: a, endSymbol: s } = e, i = await l.readFile(n, "utf-8");
310
+ let r = a;
311
+ a === "[" && (r = "\\["), a === "{" && (r = "\\{"), a === "(" && (r = "\\(");
312
+ const f = new RegExp(`${t}\\s*:\\s*(${r})`), m = i.match(f);
313
+ if (!m)
314
+ return null;
315
+ const y = i.indexOf(m[0]) + m[0].length - 1, p = ie(i, y, a, s);
316
+ return i.substring(y, p);
317
+ }, re = (e) => JSON.parse(
318
+ 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, n, t, a) => {
320
+ let s = await E(t);
321
+ if (s || (s = await E(a)), !s)
322
+ throw new Error(
323
+ `Could not find property '${t.property}' or fallback property '${a.property}' in file ${t.filePath}`
324
+ );
325
+ const i = q(JSON.stringify(n, null, 2));
326
+ return (await l.readFile(t.filePath, "utf-8")).replace(s, (f) => `${f},
327
+ ${e}: ${i}`);
328
+ }, T = (e, n) => Array.isArray(e) ? e.map(n) : [], le = (e, n) => ({
329
+ id: e.id,
330
+ language: e.language,
331
+ name: e.name,
332
+ label: e.label,
333
+ pages: T(e.pages, (t) => n.find((a) => a.id === t))
334
+ }), ge = (e, n) => ({
335
+ id: e.id,
336
+ language: e.language,
337
+ index: e.index,
338
+ folders: T(e.folders, (t) => le(t, n))
339
+ });
340
+ let v = null;
341
+ const de = (e) => {
342
+ v = oe({ accessToken: e });
343
+ }, F = () => {
344
+ if (!v)
345
+ throw new Error("API client not initialized. Call initializeClient first.");
346
+ return v;
347
+ }, ue = async () => await F().getProject(), O = async (e) => {
348
+ const n = F(), t = await n.getContent({
349
+ contentType: "Root",
350
+ includeRelatedContent: !0,
351
+ language: e
352
+ });
353
+ if (!t)
354
+ throw new Error(`Root content not found for language: ${e}`);
355
+ const a = t.folders?.flatMap((i) => i.pages) || [], s = await n.getContentList({
356
+ contentType: "Page",
357
+ id: {
358
+ in: a
359
+ },
360
+ language: e
361
+ });
362
+ if (!s)
363
+ throw new Error(`Pages not found for IDs: ${a.join(", ")}`);
364
+ return ge(t, s);
365
+ }, fe = async () => {
366
+ try {
367
+ return await F().getContent({
368
+ contentType: "Meta"
369
+ });
370
+ } catch {
371
+ o.error("The requested template is not of type StarLight, so the meta field could not be found."), process.exit(1);
372
+ }
373
+ }, U = "astro.config.mjs", P = () => g.join(process.cwd(), "src", "content", "docs"), L = () => g.join(process.cwd(), U), me = () => {
374
+ const e = [], n = L();
375
+ w(n) || e.push(U);
376
+ const t = P();
377
+ return w(t) || e.push("src/content/docs directory"), {
378
+ valid: e.length === 0,
379
+ missingItems: e
380
+ };
381
+ }, pe = async () => {
382
+ const e = P();
383
+ if (!w(e)) {
384
+ o.info("Content docs directory not found, creating it..."), await l.mkdir(e, { recursive: !0 });
385
+ return;
386
+ }
387
+ const n = await l.readdir(e);
388
+ for (const t of n) {
389
+ const a = g.join(e, t);
390
+ await l.rm(a, { recursive: !0, force: !0 });
391
+ }
392
+ }, h = {
393
+ sidebar: { start: "[", end: "]" },
394
+ locales: { start: "{", end: "}" },
395
+ title: { start: "'", end: "'" }
396
+ }, W = (e, n) => {
397
+ const t = [];
398
+ for (const a of n) {
399
+ const s = e.findIndex((i) => i.label === a.label);
400
+ if (s >= 0) {
401
+ const i = a.items && e[s].items ? W(e[s].items || [], a.items) : a.items;
402
+ t[s] = {
403
+ ...e[s],
404
+ ...a,
405
+ items: i
406
+ };
407
+ } else
408
+ t.push(a);
409
+ }
410
+ return t;
411
+ }, we = (e, n) => {
412
+ const t = {
413
+ root: { lang: e, label: M[e] }
414
+ };
415
+ return Array.isArray(n) ? n.reduce(
416
+ (a, s) => ({
417
+ ...a,
418
+ [s]: { lang: s, label: M[s] }
419
+ }),
420
+ t
421
+ ) : t;
422
+ }, D = async (e, n, t) => {
423
+ const a = L(), s = await E({
424
+ filePath: a,
425
+ property: n,
426
+ startSymbol: h[n]?.start,
427
+ endSymbol: h[n]?.end
428
+ });
429
+ let i;
430
+ if (s) {
431
+ const r = q(JSON.stringify(e, null, 2));
432
+ i = (await l.readFile(a, "utf-8")).replace(s, r);
433
+ } else
434
+ i = await ce(
435
+ n,
436
+ e,
437
+ {
438
+ filePath: a,
439
+ property: t,
440
+ startSymbol: h[t]?.start,
441
+ endSymbol: h[t]?.end
442
+ },
443
+ {
444
+ filePath: a,
445
+ property: "title",
446
+ startSymbol: h.title.start,
447
+ endSymbol: h.title.end
448
+ }
449
+ );
450
+ await l.writeFile(a, i, "utf-8");
451
+ }, he = async (e, n, t) => {
452
+ try {
453
+ let a = await E({
454
+ filePath: L(),
455
+ property: "sidebar",
456
+ startSymbol: h.sidebar.start,
457
+ endSymbol: h.sidebar.end
458
+ }), s = [];
459
+ try {
460
+ s = a ? re(a) : null;
461
+ } catch {
462
+ o.warning("Could not parse existing sidebar in astro.config.mjs. A new sidebar will be created."), s = [];
463
+ }
464
+ s || (o.warning("No existing sidebar found in astro.config.mjs. A new sidebar will be created."), s = []);
465
+ const i = W(s, e);
466
+ await D(i, "sidebar", "locales");
467
+ const r = we(n, t);
468
+ await D(r, "locales", "sidebar");
469
+ } catch (a) {
470
+ o.error(`Error reading astro.config.mjs: ${a.message}`), process.exit(1);
471
+ }
472
+ }, ye = (e) => /^---\s*\n([\s\S]*?)\n---\s*\n/.test(e), ke = (e) => g.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(" ");
473
+ function Ce(e, n, t) {
474
+ if (ye(e))
475
+ return e;
476
+ const a = ke(n), s = `---
477
+ title: "${a}"
478
+ ---
479
+
480
+ `;
481
+ return o.warning(`Missing frontmatter in ${t}`), o.info(`Added default title: "${a}"`), o.warning("Please update the content in Content Island 🏝️ to include proper frontmatter"), o.newLine(), s + e;
482
+ }
483
+ const I = async (e, n) => {
484
+ const t = P(), a = g.join(t, e), s = Ce(n, e, g.relative(process.cwd(), a)), i = g.dirname(a);
485
+ w(i) || await l.mkdir(i, { recursive: !0 }), await l.writeFile(a, s, "utf-8");
486
+ }, Se = async (e, n) => {
487
+ try {
488
+ await I(e.index.filename, e.index.content);
489
+ for (const t of e.folders)
490
+ for (const a of t.pages)
491
+ await I(g.join(t.name, a.filename), a.content);
492
+ for (const t of n) {
493
+ await I(g.join(t.language, t.index.filename), t.index.content);
494
+ for (const a of t.folders)
495
+ for (const s of a.pages)
496
+ await I(g.join(t.language, a.name, s.filename), s.content);
497
+ }
498
+ } catch (t) {
499
+ o.error(`Error updating docs content: ${t.message}`), process.exit(1);
500
+ }
501
+ }, be = async (e, n) => {
502
+ if (e.length === 1) {
503
+ const s = e[0];
504
+ return o.success(`Single language found: ${s}. Continuing...`), await b({ languageCode: s }), s;
505
+ }
506
+ const t = (await j())?.languageCode;
507
+ if (t && !n) {
508
+ if (e.includes(t))
509
+ return o.info(`Using saved default language: ${t}`), t;
510
+ o.warning(`Saved language '${t}' not found in project languages`), o.step("Will ask for new default language and save it");
511
+ }
512
+ o.step("Multiple languages found. Please select the default language:");
513
+ const a = await S({
514
+ type: "select",
515
+ name: "language",
516
+ message: "Select the default language:",
517
+ choices: e.map((s) => ({
518
+ title: s,
519
+ value: s
520
+ })),
521
+ initial: 0
522
+ });
523
+ return a.language || (o.error("Language selection is required to continue."), process.exit(1)), t !== a.language && (await b({ languageCode: a.language }), o.config(`Saving default language '${a.language}' to config`)), a.language;
524
+ }, $e = () => {
525
+ o.detected(`
526
+ ⭐ ✨ STARLIGHT PROJECT DETECTED ✨ ⭐
527
+
528
+ ⭐ ✨ ⭐ ✨
529
+ ✨ ⭐ ✨ ⭐ ✨
530
+ ⭐ ✨ ⭐ ✨ ⭐
531
+ ✨ S T A R L I G H T ✨
532
+ ⭐ ✨ ⭐ ✨ ⭐
533
+ ✨ ⭐ ✨ ⭐ ✨
534
+ ⭐ ✨ ⭐ ✨
535
+ `), o.success("All good! Starlight ⭐ project detected successfully."), o.loading("Launching process..."), o.newLine();
536
+ }, Ie = (e) => {
537
+ o.newLine(), o.error("Starlight ⭐ project not found!"), o.newLine(), o.error("Missing required items:"), e.forEach((n) => {
538
+ o.error(` • ${n}`);
539
+ }), 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();
540
+ }, Y = (e) => {
541
+ const n = e.reduce(
542
+ (t, a) => ({ ...t, ...a }),
543
+ {}
544
+ );
545
+ return Object.keys(n).length > 0 ? n : void 0;
546
+ }, H = (e) => e.filename.replace(/\.(mdx?|md)$/, ""), _ = (e) => e.label ? e.label.trim() : H(e), Ee = (e, n) => {
547
+ const t = H(e), a = n.trim().toLowerCase();
548
+ return t.toLocaleLowerCase() === "index" ? a : `${a}/${t}`;
549
+ }, Te = (e, n, t) => {
550
+ e.filename.replace(/\.(mdx?|md)$/, "");
551
+ const a = t.filter((s) => s.id === e.id).map((s) => ({ [s.language]: _(s) }));
552
+ return {
553
+ label: _(e),
554
+ slug: Ee(e, n),
555
+ translations: Y(a)
556
+ };
557
+ }, R = (e) => e.label ? e.label.trim() : e.name, ve = (e, n) => {
558
+ const t = n.flatMap((i) => i.folders ?? []).filter((i) => i.id === e.id), a = t.flatMap((i) => i.pages ?? []).filter((i) => e.pages.some((r) => r.id === i.id)), s = t.map((i) => ({ [i.language]: R(i) }));
559
+ return {
560
+ label: R(e),
561
+ translations: Y(s),
562
+ items: T(e.pages, (i) => Te(i, e.name, a))
563
+ };
564
+ }, xe = (e, n) => T(e.folders, (t) => ve(t, n)), Ae = () => ({
565
+ id: "starlight",
566
+ syncProject: async (e) => {
567
+ const { accessToken: n, askIfMultipleLanguages: t } = e;
568
+ o.step("Checking for Starlight ⭐ project...");
569
+ const { valid: a, missingItems: s } = me();
570
+ a || (Ie(s), process.exit(1)), $e(), o.connecting("Initializing Content Island 🏝️ client..."), de(n);
571
+ const i = await fe();
572
+ o.success(`Connected to project using template: ${i.template} (version: ${i.version})`), i.template !== "starlight" && (o.warning(
573
+ "The project you are trying to sync is not using the Starlight ⭐ template. Please make sure you are using the correct template."
574
+ ), process.exit(1)), await b({
575
+ version: i.version
576
+ }), o.fetching("Fetching project information from Content Island 🏝️ ...");
577
+ const r = await ue();
578
+ o.success(`Project fetched: ${r.name}`);
579
+ const f = r.languages.map((k) => k);
580
+ o.info(`Languages found (${f.length}): ${f.join(", ")}`);
581
+ const m = await be(f, t);
582
+ o.language(m);
583
+ const y = f.filter((k) => k !== m), p = await O(m);
584
+ let d = [];
585
+ for (const k of y) {
586
+ const ne = await O(k);
587
+ d.push(ne);
588
+ }
589
+ o.clearing("Clearing existing docs content..."), await pe(), o.docs("Existing docs content cleared"), o.updating("Updating docs content with fetched data..."), await Se(p, d), o.docs("Docs content updated"), o.config("Generating sidebar configuration...");
590
+ const te = xe(p, d);
591
+ await he(te, m, y), o.config("Sidebar configuration updated in astro.config.mjs");
592
+ }
593
+ }), V = {
594
+ starlight: Ae
595
+ }, je = (e) => {
596
+ const n = V[e];
597
+ if (!n)
598
+ throw new Error(`Template "${e}" not found`);
599
+ return n();
600
+ }, Fe = () => Object.keys(V), Pe = async (e, n) => {
601
+ let t;
602
+ return t || (t = (await j())?.templateID), t && n && (o.info(`Existing template found: ${t}`), (await S({
603
+ type: "confirm",
604
+ name: "useExisting",
605
+ message: `An existing template (${t}) was found. Do you want to use it?`,
606
+ initial: !0
607
+ }))?.useExisting ? o.success(`Using existing template: ${t}`) : (t = null, o.step("Selecting new template..."))), t || (o.step("Please select a template:"), t = (await S({
608
+ type: "select",
609
+ name: "templateID",
610
+ message: "Select a template:",
611
+ choices: e.map((s) => ({ title: s, value: s }))
612
+ }))?.templateID), t || (o.error("Template is required to continue"), process.exit(1)), t;
613
+ }, Z = async (e) => {
614
+ try {
615
+ const { selectedTemplateId: n, askIfExists: t } = e, a = Fe();
616
+ let s = a.find((i) => i === n);
617
+ return s || (s = await Pe(a, t)), o.detected(`Template selected: ${s}`), je(s);
618
+ } catch (n) {
619
+ o.error(`Error configuring template: ${n.message}`), process.exit(1);
620
+ }
621
+ }, z = ".env", X = "CONTENT_ISLAND_ACCESS_TOKEN", Le = async (e) => {
622
+ switch (e) {
623
+ case "starlight":
624
+ return await K(), g.join(A(), z);
625
+ default:
626
+ return g.join(process.cwd(), z);
627
+ }
628
+ }, Ne = async (e) => {
629
+ if (!w(e))
630
+ return null;
631
+ try {
632
+ const t = (await l.readFile(e, "utf-8")).match(new RegExp(`${X}=(.+)`));
633
+ return t ? t[1].trim() : null;
634
+ } catch {
635
+ return null;
636
+ }
637
+ }, Q = async (e, n) => {
638
+ try {
639
+ const t = `${X}=${e}
640
+ `;
641
+ await l.writeFile(n, t, "utf-8"), o.token(`Access token saved to ${n}`);
642
+ } catch (t) {
643
+ o.error(`Failed to save the access token: ${t.message}`);
644
+ }
645
+ }, B = (e) => {
646
+ e || (o.error("Token is required to continue"), process.exit(1));
647
+ }, Me = async (e, n) => {
648
+ let t = await Ne(e);
649
+ if (t && n && (o.info("Found existing Content Island 🏝️ token"), (await S({
650
+ type: "confirm",
651
+ name: "useExisting",
652
+ message: "An existing token was found. Do you want to use it?",
653
+ initial: !0
654
+ }))?.useExisting || (t = null)), t)
655
+ o.success("Using existing Content Island 🏝️ token");
656
+ else {
657
+ n || o.warning("No existing token found");
658
+ const a = await S({
659
+ type: "password",
660
+ name: "token",
661
+ message: "Enter your Content Island 🏝️ API token:",
662
+ validate: (s) => s.length > 0 ? !0 : "Token is required"
663
+ });
664
+ B(a?.token), t = a?.token, await Q(t, e);
665
+ }
666
+ return B(t), t;
667
+ }, ee = async (e) => {
668
+ const { accessToken: n, templateID: t, askIfExists: a } = e;
669
+ let s = n;
670
+ const i = await Le(t);
671
+ return s ? (o.success("Using provided Content Island 🏝️ token"), await Q(s, i)) : s = await Me(i, a), s;
672
+ }, Oe = async (e) => {
673
+ try {
674
+ o.title("Content Island Integration"), o.step("Configuring template...");
675
+ const n = await Z({ selectedTemplateId: e.template, askIfExists: !0 });
676
+ o.step("Saving configuration..."), await b({ templateID: n.id }), o.config("Template configuration saved"), o.step("Configuring access token...");
677
+ const t = await ee({
678
+ accessToken: e.token,
679
+ templateID: n.id,
680
+ askIfExists: !0
681
+ });
682
+ o.token("Access token configured successfully"), o.step("Synchronizing project..."), await n.syncProject({ accessToken: t, askIfMultipleLanguages: !0 }), o.docs("Project synchronized with Content Island"), o.newLine(), o.complete("Content Island 🏝️ integration completed successfully!");
683
+ } catch (n) {
684
+ o.newLine(), o.error("Error during Content Island integration:"), o.error(n instanceof Error ? n.message : String(n)), process.exit(1);
685
+ }
686
+ }, De = async () => {
687
+ try {
688
+ o.title("Content Island Integration"), o.step("Configuring template...");
689
+ const e = await Z({ askIfExists: !1 });
690
+ o.step("Saving configuration..."), await b({ templateID: e.id }), o.config("Template configuration saved"), o.step("Configuring access token...");
691
+ const n = await ee({
692
+ templateID: e.id,
693
+ askIfExists: !1
694
+ });
695
+ o.token("Access token configured successfully"), o.step("Synchronizing project..."), await e.syncProject({ accessToken: n, askIfMultipleLanguages: !1 }), o.docs("Project synchronized with Content Island"), o.newLine(), o.complete("Content Island 🏝️ integration completed successfully!");
696
+ } catch (e) {
697
+ o.newLine(), o.error("Error during Content Island integration:"), o.error(e instanceof Error ? e.message : String(e)), process.exit(1);
698
+ }
699
+ }, _e = "0.0.1", Re = {
700
+ version: _e
701
+ }, $ = ae("create-contentisland");
702
+ $.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(
703
+ "--token <token>",
704
+ "Your Content Island token (you can also set the CONTENT_ISLAND_ACCESS_TOKEN environment variable)",
705
+ {
706
+ default: process.env.CONTENT_ISLAND_ACCESS_TOKEN || void 0
707
+ }
708
+ ).option("--template <template>", "The template to use: starlight.").action(async (e) => {
709
+ await Oe(e);
710
+ });
711
+ $.command("update", "Update content from Content Island 🏝️ (preserves existing token)").example("npm create contentisland update").action(async () => {
712
+ await De();
713
+ });
714
+ $.help();
715
+ $.version(Re.version);
716
+ $.parse();
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "create-contentisland",
3
+ "version": "0.0.1",
4
+ "description": "Content Island - Starlight CLI",
5
+ "private": false,
6
+ "sideEffects": false,
7
+ "author": "Lemoncode",
8
+ "license": "MIT",
9
+ "files": [
10
+ "cli.js",
11
+ "dist"
12
+ ],
13
+ "bin": {
14
+ "create-contentisland": "./cli.js"
15
+ },
16
+ "type": "module",
17
+ "imports": {
18
+ "#**": "./src/*"
19
+ },
20
+ "scripts": {
21
+ "start:console-runners": "run-p type-check:watch console-runners",
22
+ "console-runners": "tsx --watch src/console-runners/index.ts",
23
+ "build": "vite build",
24
+ "type-check": "tsc --noEmit --preserveWatchOutput",
25
+ "type-check:watch": "npm run type-check -- --watch",
26
+ "test": "vitest run -c ./config/test/config.ts",
27
+ "test:watch": "vitest -c ./config/test/config.ts"
28
+ },
29
+ "dependencies": {
30
+ "@content-island/api-client": "0.11.0",
31
+ "cac": "6.7.14",
32
+ "prompts": "2.4.2"
33
+ },
34
+ "devDependencies": {
35
+ "@content-island/common": "*"
36
+ }
37
+ }