create-contentisland 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -0
- package/dist/index.js +39 -37
- package/package.json +2 -2
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# create-contentisland
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The Content Island CLI allows you to quickly bootstrap codebase
|
|
6
|
+
solutions and connect them to your Content Island projects.
|
|
7
|
+
|
|
8
|
+
Currently, the following template is available:
|
|
9
|
+
|
|
10
|
+
- **Starlight Template**
|
|
11
|
+
|
|
12
|
+
> Additional templates will be added soon.
|
|
13
|
+
|
|
14
|
+
## Using the Starlight Template
|
|
15
|
+
|
|
16
|
+
### Prerequisites
|
|
17
|
+
|
|
18
|
+
- A [Content Island](https://contentisland.net/) account (free plans are available).
|
|
19
|
+
- A new [Content Island](https://contentisland.net/) project created with the **Starlight
|
|
20
|
+
template**.
|
|
21
|
+
|
|
22
|
+
### Step 1 --- Create a Starlight project
|
|
23
|
+
|
|
24
|
+
Run the following command to create a new [Starlight](https://starlight.astro.build/) project and install
|
|
25
|
+
its dependencies:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm create astro@latest -- --template starlight
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Step 2 --- Connect your Content Island project
|
|
32
|
+
|
|
33
|
+
Once your Starlight project has been created, connect it to your Content
|
|
34
|
+
Island project:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm create contentisland@latest
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
When prompted, provide your **Content Island Project API token**. You
|
|
41
|
+
can copy this token from the **General** tab of your Content Island
|
|
42
|
+
project settings.
|
|
43
|
+
|
|
44
|
+
### Step 3 --- Sync your content
|
|
45
|
+
|
|
46
|
+
The CLI will automatically replace the contents of the `content/docs`
|
|
47
|
+
folder with the content from your Content Island project.
|
|
48
|
+
|
|
49
|
+
You can then run your project locally:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm run dev
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Step 4 --- Update content
|
|
56
|
+
|
|
57
|
+
Manage your content directly in Content Island---add, edit, or delete
|
|
58
|
+
folders and pages. To update your local Starlight project with the
|
|
59
|
+
latest content, run:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm create contentisland@latest update
|
|
63
|
+
```
|
package/dist/index.js
CHANGED
|
@@ -305,7 +305,7 @@ const x = ".content-island", G = "config.json", N = ".gitignore", M = {
|
|
|
305
305
|
}
|
|
306
306
|
}
|
|
307
307
|
return i;
|
|
308
|
-
},
|
|
308
|
+
}, v = async (e) => {
|
|
309
309
|
const { filePath: n, property: t, startSymbol: a, endSymbol: s } = e, i = await l.readFile(n, "utf-8");
|
|
310
310
|
let r = a;
|
|
311
311
|
a === "[" && (r = "\\["), a === "{" && (r = "\\{"), a === "(" && (r = "\\(");
|
|
@@ -317,8 +317,8 @@ const x = ".content-island", G = "config.json", N = ".gitignore", M = {
|
|
|
317
317
|
}, re = (e) => JSON.parse(
|
|
318
318
|
e.replace(/'/g, '"').replace(/(\w+):/g, '"$1":').replace(/,\s*}/g, "}").replace(/,\s*]/g, "]")
|
|
319
319
|
), q = (e) => e.replace(/"/g, "'").replace(/'(\w+)':/g, "$1:"), ce = async (e, n, t, a) => {
|
|
320
|
-
let s = await
|
|
321
|
-
if (s || (s = await
|
|
320
|
+
let s = await v(t);
|
|
321
|
+
if (s || (s = await v(a)), !s)
|
|
322
322
|
throw new Error(
|
|
323
323
|
`Could not find property '${t.property}' or fallback property '${a.property}' in file ${t.filePath}`
|
|
324
324
|
);
|
|
@@ -337,13 +337,13 @@ const x = ".content-island", G = "config.json", N = ".gitignore", M = {
|
|
|
337
337
|
index: e.index,
|
|
338
338
|
folders: T(e.folders, (t) => le(t, n))
|
|
339
339
|
});
|
|
340
|
-
let
|
|
340
|
+
let E = null;
|
|
341
341
|
const de = (e) => {
|
|
342
|
-
|
|
342
|
+
E = oe({ accessToken: e });
|
|
343
343
|
}, F = () => {
|
|
344
|
-
if (!
|
|
344
|
+
if (!E)
|
|
345
345
|
throw new Error("API client not initialized. Call initializeClient first.");
|
|
346
|
-
return
|
|
346
|
+
return E;
|
|
347
347
|
}, ue = async () => await F().getProject(), O = async (e) => {
|
|
348
348
|
const n = F(), t = await n.getContent({
|
|
349
349
|
contentType: "Root",
|
|
@@ -367,8 +367,10 @@ const de = (e) => {
|
|
|
367
367
|
return await F().getContent({
|
|
368
368
|
contentType: "Meta"
|
|
369
369
|
});
|
|
370
|
-
} catch {
|
|
371
|
-
|
|
370
|
+
} catch (e) {
|
|
371
|
+
e.message.includes("401") ? o.error(
|
|
372
|
+
"The Content Island API token is missing or malformed. Verify that you've copied the complete token and that you have sufficient permissions."
|
|
373
|
+
) : o.error("The requested template is not of type StarLight, so the meta field could not be found."), process.exit(1);
|
|
372
374
|
}
|
|
373
375
|
}, U = "astro.config.mjs", P = () => g.join(process.cwd(), "src", "content", "docs"), L = () => g.join(process.cwd(), U), me = () => {
|
|
374
376
|
const e = [], n = L();
|
|
@@ -420,7 +422,7 @@ const de = (e) => {
|
|
|
420
422
|
t
|
|
421
423
|
) : t;
|
|
422
424
|
}, D = async (e, n, t) => {
|
|
423
|
-
const a = L(), s = await
|
|
425
|
+
const a = L(), s = await v({
|
|
424
426
|
filePath: a,
|
|
425
427
|
property: n,
|
|
426
428
|
startSymbol: h[n]?.start,
|
|
@@ -450,7 +452,7 @@ const de = (e) => {
|
|
|
450
452
|
await l.writeFile(a, i, "utf-8");
|
|
451
453
|
}, he = async (e, n, t) => {
|
|
452
454
|
try {
|
|
453
|
-
let a = await
|
|
455
|
+
let a = await v({
|
|
454
456
|
filePath: L(),
|
|
455
457
|
property: "sidebar",
|
|
456
458
|
startSymbol: h.sidebar.start,
|
|
@@ -480,20 +482,20 @@ title: "${a}"
|
|
|
480
482
|
`;
|
|
481
483
|
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
484
|
}
|
|
483
|
-
const
|
|
485
|
+
const $ = async (e, n) => {
|
|
484
486
|
const t = P(), a = g.join(t, e), s = Ce(n, e, g.relative(process.cwd(), a)), i = g.dirname(a);
|
|
485
487
|
w(i) || await l.mkdir(i, { recursive: !0 }), await l.writeFile(a, s, "utf-8");
|
|
486
488
|
}, Se = async (e, n) => {
|
|
487
489
|
try {
|
|
488
|
-
await
|
|
490
|
+
await $(e.index.filename, e.index.content);
|
|
489
491
|
for (const t of e.folders)
|
|
490
492
|
for (const a of t.pages)
|
|
491
|
-
await
|
|
493
|
+
await $(g.join(t.name, a.filename), a.content);
|
|
492
494
|
for (const t of n) {
|
|
493
|
-
await
|
|
495
|
+
await $(g.join(t.language, t.index.filename), t.index.content);
|
|
494
496
|
for (const a of t.folders)
|
|
495
497
|
for (const s of a.pages)
|
|
496
|
-
await
|
|
498
|
+
await $(g.join(t.language, a.name, s.filename), s.content);
|
|
497
499
|
}
|
|
498
500
|
} catch (t) {
|
|
499
501
|
o.error(`Error updating docs content: ${t.message}`), process.exit(1);
|
|
@@ -521,7 +523,7 @@ const I = async (e, n) => {
|
|
|
521
523
|
initial: 0
|
|
522
524
|
});
|
|
523
525
|
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
|
-
},
|
|
526
|
+
}, Ie = () => {
|
|
525
527
|
o.detected(`
|
|
526
528
|
⭐ ✨ STARLIGHT PROJECT DETECTED ✨ ⭐
|
|
527
529
|
|
|
@@ -533,41 +535,41 @@ const I = async (e, n) => {
|
|
|
533
535
|
✨ ⭐ ✨ ⭐ ✨
|
|
534
536
|
⭐ ✨ ⭐ ✨
|
|
535
537
|
`), o.success("All good! Starlight ⭐ project detected successfully."), o.loading("Launching process..."), o.newLine();
|
|
536
|
-
},
|
|
538
|
+
}, $e = (e) => {
|
|
537
539
|
o.newLine(), o.error("Starlight ⭐ project not found!"), o.newLine(), o.error("Missing required items:"), e.forEach((n) => {
|
|
538
540
|
o.error(` • ${n}`);
|
|
539
541
|
}), 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
|
-
},
|
|
542
|
+
}, V = (e) => {
|
|
541
543
|
const n = e.reduce(
|
|
542
544
|
(t, a) => ({ ...t, ...a }),
|
|
543
545
|
{}
|
|
544
546
|
);
|
|
545
547
|
return Object.keys(n).length > 0 ? n : void 0;
|
|
546
|
-
},
|
|
547
|
-
const t =
|
|
548
|
+
}, Y = (e) => e.filename.replace(/\.(mdx?|md)$/, ""), _ = (e) => e.label ? e.label.trim() : Y(e), ve = (e, n) => {
|
|
549
|
+
const t = Y(e), a = n.trim().toLowerCase();
|
|
548
550
|
return t.toLocaleLowerCase() === "index" ? a : `${a}/${t}`;
|
|
549
551
|
}, Te = (e, n, t) => {
|
|
550
552
|
e.filename.replace(/\.(mdx?|md)$/, "");
|
|
551
553
|
const a = t.filter((s) => s.id === e.id).map((s) => ({ [s.language]: _(s) }));
|
|
552
554
|
return {
|
|
553
555
|
label: _(e),
|
|
554
|
-
slug:
|
|
555
|
-
translations:
|
|
556
|
+
slug: ve(e, n),
|
|
557
|
+
translations: V(a)
|
|
556
558
|
};
|
|
557
|
-
}, R = (e) => e.label ? e.label.trim() : e.name,
|
|
559
|
+
}, R = (e) => e.label ? e.label.trim() : e.name, Ee = (e, n) => {
|
|
558
560
|
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
561
|
return {
|
|
560
562
|
label: R(e),
|
|
561
|
-
translations:
|
|
563
|
+
translations: V(s),
|
|
562
564
|
items: T(e.pages, (i) => Te(i, e.name, a))
|
|
563
565
|
};
|
|
564
|
-
}, xe = (e, n) => T(e.folders, (t) =>
|
|
566
|
+
}, xe = (e, n) => T(e.folders, (t) => Ee(t, n)), Ae = () => ({
|
|
565
567
|
id: "starlight",
|
|
566
568
|
syncProject: async (e) => {
|
|
567
569
|
const { accessToken: n, askIfMultipleLanguages: t } = e;
|
|
568
570
|
o.step("Checking for Starlight ⭐ project...");
|
|
569
571
|
const { valid: a, missingItems: s } = me();
|
|
570
|
-
a || (
|
|
572
|
+
a || ($e(s), process.exit(1)), Ie(), o.connecting("Initializing Content Island 🏝️ client..."), de(n);
|
|
571
573
|
const i = await fe();
|
|
572
574
|
o.success(`Connected to project using template: ${i.template} (version: ${i.version})`), i.template !== "starlight" && (o.warning(
|
|
573
575
|
"The project you are trying to sync is not using the Starlight ⭐ template. Please make sure you are using the correct template."
|
|
@@ -590,14 +592,14 @@ const I = async (e, n) => {
|
|
|
590
592
|
const te = xe(p, d);
|
|
591
593
|
await he(te, m, y), o.config("Sidebar configuration updated in astro.config.mjs");
|
|
592
594
|
}
|
|
593
|
-
}),
|
|
595
|
+
}), H = {
|
|
594
596
|
starlight: Ae
|
|
595
597
|
}, je = (e) => {
|
|
596
|
-
const n =
|
|
598
|
+
const n = H[e];
|
|
597
599
|
if (!n)
|
|
598
600
|
throw new Error(`Template "${e}" not found`);
|
|
599
601
|
return n();
|
|
600
|
-
}, Fe = () => Object.keys(
|
|
602
|
+
}, Fe = () => Object.keys(H), Pe = async (e, n) => {
|
|
601
603
|
let t;
|
|
602
604
|
return t || (t = (await j())?.templateID), t && n && (o.info(`Existing template found: ${t}`), (await S({
|
|
603
605
|
type: "confirm",
|
|
@@ -696,10 +698,10 @@ const I = async (e, n) => {
|
|
|
696
698
|
} catch (e) {
|
|
697
699
|
o.newLine(), o.error("Error during Content Island integration:"), o.error(e instanceof Error ? e.message : String(e)), process.exit(1);
|
|
698
700
|
}
|
|
699
|
-
}, _e = "0.0.
|
|
701
|
+
}, _e = "0.0.3", Re = {
|
|
700
702
|
version: _e
|
|
701
|
-
},
|
|
702
|
-
|
|
703
|
+
}, I = ae("create-contentisland");
|
|
704
|
+
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(
|
|
703
705
|
"--token <token>",
|
|
704
706
|
"Your Content Island token (you can also set the CONTENT_ISLAND_ACCESS_TOKEN environment variable)",
|
|
705
707
|
{
|
|
@@ -708,9 +710,9 @@ $.command("", "Initialize and validate a project").example("npm create contentis
|
|
|
708
710
|
).option("--template <template>", "The template to use: starlight.").action(async (e) => {
|
|
709
711
|
await Oe(e);
|
|
710
712
|
});
|
|
711
|
-
|
|
713
|
+
I.command("update", "Update content from Content Island 🏝️ (preserves existing token)").example("npm create contentisland update").action(async () => {
|
|
712
714
|
await De();
|
|
713
715
|
});
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
716
|
+
I.help();
|
|
717
|
+
I.version(Re.version);
|
|
718
|
+
I.parse();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-contentisland",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Content Island - Starlight CLI",
|
|
5
5
|
"private": false,
|
|
6
6
|
"sideEffects": false,
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"test:watch": "vitest -c ./config/test/config.ts"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@content-island/api-client": "0.
|
|
30
|
+
"@content-island/api-client": "0.12.0",
|
|
31
31
|
"cac": "6.7.14",
|
|
32
32
|
"prompts": "2.4.2"
|
|
33
33
|
},
|