create-pluto 0.0.1-alpha.3 → 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.
- package/.github/dependabot.yml +10 -0
- package/.github/workflows/ci.yml +28 -0
- package/.github/workflows/release.yml +59 -0
- package/.release-please-manifest.json +3 -0
- package/.vscode/extensions.json +2 -1
- package/.vscode/settings.json +1 -8
- package/CHANGELOG.md +31 -0
- package/LICENSE +20 -20
- package/README.md +12 -0
- package/bin/cli.mjs +1 -1
- package/bun.lock +611 -4
- package/dist/index.mjs +2 -144
- package/eslint.config.mjs +30 -0
- package/package.json +19 -13
- package/release-please-config.json +9 -0
- package/tsconfig.json +15 -9
- package/tsdown.config.ts +1 -0
- package/.env +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,144 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import fs from "fs";
|
|
4
|
-
|
|
5
|
-
//#region src/choices/supabase-template.ts
|
|
6
|
-
async function setupSupabase() {
|
|
7
|
-
let supabaseUrl;
|
|
8
|
-
let supabaseKey;
|
|
9
|
-
while (!supabaseUrl) {
|
|
10
|
-
supabaseUrl = await text$1({ message: "Type/Paste your Supabase URL:" });
|
|
11
|
-
if (!supabaseUrl || typeof supabaseUrl !== "string") log.error("Supabase URL is required.");
|
|
12
|
-
}
|
|
13
|
-
while (!supabaseKey) {
|
|
14
|
-
supabaseKey = await text$1({ message: "Type/Paste your Supabase Key:" });
|
|
15
|
-
if (!supabaseKey || typeof supabaseKey !== "string") log.error("Supabase Key is required.");
|
|
16
|
-
}
|
|
17
|
-
return {
|
|
18
|
-
supabaseUrl,
|
|
19
|
-
supabaseKey
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
function setupSupabaseEnvVars(supabaseUrl, supabaseKey) {
|
|
23
|
-
let envVars = {};
|
|
24
|
-
envVars.SUPABASE_PROJECT_ID = supabaseUrl ? supabaseUrl.toString().split("//")[1]?.split(".")[0] ?? "" : "";
|
|
25
|
-
envVars.SUPABASE_URL = supabaseUrl?.toString() ?? "";
|
|
26
|
-
envVars.SUPABASE_KEY = supabaseKey?.toString() ?? "";
|
|
27
|
-
return { envVars };
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
//#endregion
|
|
31
|
-
//#region src/index.ts
|
|
32
|
-
const cwd = process.cwd();
|
|
33
|
-
const color = {
|
|
34
|
-
blue: (text) => `\x1b[34m${text}\x1b[0m`,
|
|
35
|
-
green: (text) => `\x1b[32m${text}\x1b[0m`
|
|
36
|
-
};
|
|
37
|
-
const menu = {
|
|
38
|
-
databases: [{
|
|
39
|
-
value: "supabase",
|
|
40
|
-
label: "Supabase",
|
|
41
|
-
hint: "Hosted Postgres Database"
|
|
42
|
-
}],
|
|
43
|
-
templates: [{
|
|
44
|
-
value: "shop",
|
|
45
|
-
label: "Shop (e-commerce)",
|
|
46
|
-
hint: "A full-featured online store template"
|
|
47
|
-
}]
|
|
48
|
-
};
|
|
49
|
-
const templateDir = await text$1({
|
|
50
|
-
message: "Where do you want to create your Pluto project?",
|
|
51
|
-
placeholder: "./my-pluto-project",
|
|
52
|
-
defaultValue: "my-pluto-project"
|
|
53
|
-
});
|
|
54
|
-
if (isCancel(templateDir)) {
|
|
55
|
-
cancel("Operation cancelled.");
|
|
56
|
-
process.exit(0);
|
|
57
|
-
}
|
|
58
|
-
const templatePath = `${cwd}/${templateDir}`;
|
|
59
|
-
if (!fs.existsSync(templatePath)) fs.mkdirSync(templatePath, { recursive: true });
|
|
60
|
-
const websiteTitle = await text$1({
|
|
61
|
-
message: "Website title:",
|
|
62
|
-
placeholder: "My Awesome Website",
|
|
63
|
-
defaultValue: "My Awesome Website"
|
|
64
|
-
});
|
|
65
|
-
if (isCancel(websiteTitle)) {
|
|
66
|
-
cancel("Operation cancelled.");
|
|
67
|
-
process.exit(0);
|
|
68
|
-
}
|
|
69
|
-
const databaseProvider = await select({
|
|
70
|
-
message: "Pick a database provider.",
|
|
71
|
-
options: menu.databases
|
|
72
|
-
});
|
|
73
|
-
if (isCancel(databaseProvider)) {
|
|
74
|
-
cancel("Operation cancelled.");
|
|
75
|
-
process.exit(0);
|
|
76
|
-
}
|
|
77
|
-
let supabaseUrl;
|
|
78
|
-
let supabaseKey;
|
|
79
|
-
if (databaseProvider === "supabase") {
|
|
80
|
-
log.warn(`You must have a Supabase project set up. If you do not have one, please create it at:\n${color.blue("https://database.new/")}.`);
|
|
81
|
-
const { supabaseUrl: url, supabaseKey: key } = await setupSupabase();
|
|
82
|
-
if (!url || !key) {
|
|
83
|
-
log.error("Supabase setup failed.");
|
|
84
|
-
process.exit(1);
|
|
85
|
-
}
|
|
86
|
-
supabaseUrl = url;
|
|
87
|
-
supabaseKey = key;
|
|
88
|
-
}
|
|
89
|
-
const s = spinner();
|
|
90
|
-
if (fs.existsSync(`${cwd}/nuxt.config.ts`)) {
|
|
91
|
-
if (!await confirm({ message: "Nuxt project detected. Do you want to add Pluto environment variables?" })) process.exit(0);
|
|
92
|
-
}
|
|
93
|
-
const templateChoice = await select({
|
|
94
|
-
message: "Select a template to use. You can add more layers as needed.",
|
|
95
|
-
options: menu.templates
|
|
96
|
-
});
|
|
97
|
-
if (isCancel(templateChoice)) {
|
|
98
|
-
cancel("Operation cancelled.");
|
|
99
|
-
process.exit(0);
|
|
100
|
-
}
|
|
101
|
-
if (fs.readdirSync(templatePath).length > 0) {
|
|
102
|
-
if (!await confirm({ message: `The folder ${color.green(templateDir)} is not empty. Do you want to continue and potentially overwrite existing files?` })) {
|
|
103
|
-
cancel("Operation cancelled.");
|
|
104
|
-
process.exit(0);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
s.start(`Downloading Pluto template...`);
|
|
108
|
-
const { source } = await downloadTemplate(`gh:plutocms/pluto-${databaseProvider}-${templateChoice}-template`, {
|
|
109
|
-
dir: templatePath,
|
|
110
|
-
force: true
|
|
111
|
-
});
|
|
112
|
-
log.info(`Template downloaded from ${color.green(source)}`);
|
|
113
|
-
const envPath = `${cwd}/${templateDir}/.env`;
|
|
114
|
-
const envVars = { PLUTO_WEBSITE_TITLE: websiteTitle?.toString() ?? "" };
|
|
115
|
-
if (databaseProvider === "supabase") {
|
|
116
|
-
const { envVars: supabaseEnvVars } = setupSupabaseEnvVars(supabaseUrl, supabaseKey);
|
|
117
|
-
Object.assign(envVars, supabaseEnvVars);
|
|
118
|
-
}
|
|
119
|
-
try {
|
|
120
|
-
let envContent = "";
|
|
121
|
-
if (fs.existsSync(envPath)) {
|
|
122
|
-
envContent = fs.readFileSync(envPath, "utf-8");
|
|
123
|
-
Object.entries(envVars).forEach(([key, value]) => {
|
|
124
|
-
const regex = new RegExp(`^${key}=.*$`, "m");
|
|
125
|
-
if (regex.test(envContent)) envContent = envContent.replace(regex, `${key}="${value}"`);
|
|
126
|
-
else envContent += `\n${key}="${value}"`;
|
|
127
|
-
});
|
|
128
|
-
} else {
|
|
129
|
-
envContent = "# Pluto Configurations\n";
|
|
130
|
-
Object.entries(envVars).forEach(([key, value]) => {
|
|
131
|
-
envContent += `${key}="${value}"\n`;
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
fs.writeFileSync(envPath, envContent.trim() + "\n");
|
|
135
|
-
} catch (error) {
|
|
136
|
-
log.error(`Failed to write to .env file: ${error}`);
|
|
137
|
-
process.exit(1);
|
|
138
|
-
}
|
|
139
|
-
s.stop("All done!");
|
|
140
|
-
log.success("Setup complete! 🎉");
|
|
141
|
-
log.info(`Nuxt project created in: ${color.green(templateDir)}`);
|
|
142
|
-
|
|
143
|
-
//#endregion
|
|
144
|
-
export { };
|
|
1
|
+
import e from"node:fs";import t from"node:path";import{cancel as n,confirm as r,isCancel as i,log as a,select as o,spinner as s,text as c}from"@clack/prompts";import{downloadTemplate as l}from"giget";async function u(){let e,t;for(;!e;)e=await c({message:`Type/Paste your Supabase URL:`}),(!e||typeof e!=`string`)&&a.error(`Supabase URL is required.`);for(;!t;)t=await c({message:`Type/Paste your Supabase Key:`}),(!t||typeof t!=`string`)&&a.error(`Supabase Key is required.`);return{supabaseUrl:e,supabaseKey:t}}function d(e,t){let n={};return n.SUPABASE_PROJECT_ID=e?e.toString().split(`//`)[1]?.split(`.`)[0]??``:``,n.SUPABASE_URL=e?.toString()??``,n.SUPABASE_KEY=t?.toString()??``,{envVars:n}}const f=process.cwd(),p={blue:e=>`\x1B[34m${e}\x1B[0m`,green:e=>`\x1B[32m${e}\x1B[0m`},m={databases:[{value:`supabase`,label:`Supabase`,hint:`Hosted Postgres Database`}],templates:[{value:`shop`,label:`Shop (e-commerce)`,hint:`A full-featured online store template`}]};function h(e){let t={};for(let n=0;n<e.length;n+=1){let r=e[n];if(r===`-t`||r===`--template`){t.templateShortcut=e[n+1],n+=1;continue}if(r?.startsWith(`--template=`)){t.templateShortcut=r.split(`=`)[1];continue}!r?.startsWith(`-`)&&!t.projectDir&&(t.projectDir=r)}return t}function g(e){let[t,n]=e.split(`-`,2),r=m.databases.some(e=>e.value===t),i=m.templates.some(e=>e.value===n);if(!r||!i){let t=m.databases.flatMap(e=>m.templates.map(t=>`${e.value}-${t.value}`));a.error(`Unknown template \"${e}\". Available options: ${t.join(`, `)}`),process.exit(1)}return{databaseProvider:t,templateChoice:n}}const _=h(process.argv.slice(2)),v=_.templateShortcut?g(_.templateShortcut):void 0,y=_.projectDir?_.projectDir:await c({message:`Where do you want to create your Pluto project?`,placeholder:`./my-pluto-project`,defaultValue:`my-pluto-project`});i(y)&&(n(`Operation cancelled.`),process.exit(0));const b=t.resolve(f,y);e.existsSync(b)||e.mkdirSync(b,{recursive:!0});const x=await c({message:`Website title:`,placeholder:`My Awesome Website`,defaultValue:`My Awesome Website`});i(x)&&(n(`Operation cancelled.`),process.exit(0));const S=v?v.databaseProvider:await o({message:`Pick a database provider.`,options:m.databases});i(S)&&(n(`Operation cancelled.`),process.exit(0));let C,w;if(S===`supabase`){a.warn(`You must have a Supabase project set up. If you do not have one, please create it at:\n${p.blue(`https://database.new/`)}.`);let{supabaseUrl:e,supabaseKey:t}=await u();(!e||!t)&&(a.error(`Supabase setup failed.`),process.exit(1)),C=e,w=t}const T=s();e.existsSync(`${f}/nuxt.config.ts`)&&(await r({message:`Nuxt project detected. Do you want to add Pluto environment variables?`})||process.exit(0));const E=v?v.templateChoice:await o({message:`Select a template to use. You can add more layers as needed.`,options:m.templates});i(E)&&(n(`Operation cancelled.`),process.exit(0)),e.readdirSync(b).length>0&&(await r({message:`The folder ${p.green(y)} is not empty. Do you want to continue and potentially overwrite existing files?`})||(n(`Operation cancelled.`),process.exit(0))),T.start(`Downloading Pluto template...`);const{source:D}=await l(`gh:plutocms/pluto-${S}-${E}-template`,{dir:b,force:!0});a.info(`Template downloaded from ${p.green(D)}`);const O=t.resolve(b,`.env`),k={PLUTO_WEBSITE_TITLE:x?.toString()??``};if(S===`supabase`){let{envVars:e}=d(C,w);Object.assign(k,e)}try{let t=``;e.existsSync(O)?(t=e.readFileSync(O,`utf-8`),Object.entries(k).forEach(([e,n])=>{let r=RegExp(`^${e}=.*$`,`m`);r.test(t)?t=t.replace(r,`${e}="${n}"`):t+=`\n${e}="${n}"`})):(t=`# Pluto Configurations
|
|
2
|
+
`,Object.entries(k).forEach(([e,n])=>{t+=`${e}="${n}"\n`})),e.writeFileSync(O,`${t.trim()}\n`)}catch(e){a.error(`Failed to write to .env file: ${e}`),process.exit(1)}T.stop(`All done!`),a.success(`Setup complete! 🎉`),a.info(`Nuxt project created in: ${p.green(y)}`);export{};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import antfu from '@antfu/eslint-config'
|
|
3
|
+
|
|
4
|
+
export default antfu({
|
|
5
|
+
ignores: ['**/*.md', '.github/**'],
|
|
6
|
+
|
|
7
|
+
rules: {
|
|
8
|
+
'node/prefer-global/process': ['off', 'never'],
|
|
9
|
+
|
|
10
|
+
'style/arrow-parens': ['warn', 'always'],
|
|
11
|
+
|
|
12
|
+
'style/brace-style': ['warn', '1tbs'],
|
|
13
|
+
|
|
14
|
+
'style/comma-dangle': [
|
|
15
|
+
'warn',
|
|
16
|
+
{
|
|
17
|
+
arrays: 'always-multiline',
|
|
18
|
+
objects: 'always-multiline',
|
|
19
|
+
functions: 'never',
|
|
20
|
+
imports: 'always-multiline',
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
|
|
24
|
+
'style/operator-linebreak': 'off',
|
|
25
|
+
|
|
26
|
+
// This CLI's entry point is a top-level script, not a module with a main()
|
|
27
|
+
// wrapper, so top-level await is the idiomatic way to run it.
|
|
28
|
+
'antfu/no-top-level-await': 'off',
|
|
29
|
+
},
|
|
30
|
+
})
|
package/package.json
CHANGED
|
@@ -1,21 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-pluto",
|
|
3
|
-
"version": "0.0.1-alpha.3",
|
|
4
|
-
"module": "./bin/cli.mjs",
|
|
5
3
|
"type": "module",
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "CLI Wizard for creating a Pluto App",
|
|
6
|
+
"author": "https://github.com/ojvribeiro",
|
|
9
7
|
"license": "MIT",
|
|
8
|
+
"homepage": "https://github.com/plutocms/create-pluto#readme",
|
|
10
9
|
"repository": {
|
|
11
10
|
"type": "git",
|
|
12
|
-
"url": "git+https://github.com/plutocms/pluto.git"
|
|
11
|
+
"url": "git+https://github.com/plutocms/create-pluto.git"
|
|
13
12
|
},
|
|
14
13
|
"bugs": {
|
|
15
|
-
"url": "https://github.com/plutocms/pluto/issues"
|
|
14
|
+
"url": "https://github.com/plutocms/create-pluto/issues"
|
|
16
15
|
},
|
|
17
|
-
"description": "CLI Wizard for creating a Pluto App",
|
|
18
|
-
"homepage": "https://github.com/plutocms/pluto#readme",
|
|
19
16
|
"keywords": [
|
|
20
17
|
"pluto",
|
|
21
18
|
"plutocms",
|
|
@@ -26,19 +23,28 @@
|
|
|
26
23
|
"headless",
|
|
27
24
|
"cms"
|
|
28
25
|
],
|
|
29
|
-
"
|
|
26
|
+
"main": "./src/index.ts",
|
|
27
|
+
"module": "./bin/cli.mjs",
|
|
28
|
+
"bin": {
|
|
29
|
+
"create-pluto": "bin/cli.mjs"
|
|
30
|
+
},
|
|
30
31
|
"scripts": {
|
|
31
32
|
"setup": "node src/index.ts",
|
|
32
|
-
"build": "tsdown"
|
|
33
|
+
"build": "tsdown",
|
|
34
|
+
"prettier": "prettier --write .",
|
|
35
|
+
"lint": "eslint .",
|
|
36
|
+
"lint:fix": "eslint . --fix && prettier --write ."
|
|
33
37
|
},
|
|
34
|
-
"main": "./src/index.ts",
|
|
35
38
|
"dependencies": {
|
|
36
39
|
"@clack/prompts": "^0.11.0",
|
|
37
40
|
"giget": "^3.1.1"
|
|
38
41
|
},
|
|
39
42
|
"devDependencies": {
|
|
43
|
+
"@antfu/eslint-config": "^7.4.3",
|
|
40
44
|
"@types/node": "^25.0.10",
|
|
45
|
+
"eslint": "^10.0.0",
|
|
41
46
|
"prettier": "^3.8.1",
|
|
42
|
-
"tsdown": "^0.20.1"
|
|
47
|
+
"tsdown": "^0.20.1",
|
|
48
|
+
"typescript": "^5.9.3"
|
|
43
49
|
}
|
|
44
50
|
}
|
package/tsconfig.json
CHANGED
|
@@ -1,28 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
+
"target": "ESNext",
|
|
3
4
|
// Environment setup & latest features
|
|
4
5
|
"lib": ["ESNext"],
|
|
5
|
-
"target": "ESNext",
|
|
6
|
-
"module": "nodenext",
|
|
7
6
|
"moduleDetection": "force",
|
|
8
|
-
"
|
|
7
|
+
"module": "nodenext",
|
|
9
8
|
|
|
10
9
|
// Bundler mode
|
|
11
10
|
"moduleResolution": "nodenext",
|
|
11
|
+
|
|
12
|
+
// Make Node built-in globals/modules (process, fs, path, etc.) available
|
|
13
|
+
"types": ["node"],
|
|
12
14
|
"allowImportingTsExtensions": true,
|
|
13
|
-
"
|
|
14
|
-
"noEmit": true,
|
|
15
|
+
"allowJs": true,
|
|
15
16
|
|
|
16
17
|
// Best practices
|
|
17
18
|
"strict": true,
|
|
18
|
-
"skipLibCheck": true,
|
|
19
19
|
"noFallthroughCasesInSwitch": true,
|
|
20
|
-
"noUncheckedIndexedAccess": true,
|
|
21
20
|
"noImplicitOverride": true,
|
|
22
21
|
|
|
22
|
+
"noPropertyAccessFromIndexSignature": false,
|
|
23
|
+
"noUncheckedIndexedAccess": true,
|
|
23
24
|
// Some stricter flags (disabled by default)
|
|
24
25
|
"noUnusedLocals": false,
|
|
25
26
|
"noUnusedParameters": false,
|
|
26
|
-
"
|
|
27
|
-
|
|
27
|
+
"noEmit": true,
|
|
28
|
+
"verbatimModuleSyntax": true,
|
|
29
|
+
"skipLibCheck": true
|
|
30
|
+
},
|
|
31
|
+
"include": ["src/**/*.ts", "bin/**/*.mjs"],
|
|
32
|
+
// Downloaded/generated by the CLI itself when run locally - not part of this package's own source
|
|
33
|
+
"exclude": ["node_modules", "dist", "my-pluto-project"]
|
|
28
34
|
}
|
package/tsdown.config.ts
CHANGED
package/.env
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
GIGET_AUTH=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
|