diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..f17f51b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" + diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..4b9a2d9 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "printWidth": 120, + "singleQuote": true, + "trailingComma": "all" +} diff --git a/README.md b/README.md index 4c882b1..12b3f94 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ npx create-stackbit-app@latest --starter ts-nextjs If no starter option is provided, [the default starter](https://github.com/stackbit-themes/nextjs-starter) is used. -### Starting from an Example (๐Ÿงช Experimental) +### Starting from an Example Use the `--example` option to start a project from an example. Run the command with the `--help` flag to see a full list of available starters. @@ -42,8 +42,6 @@ npx create-stackbit-app@latest --example algolia-search This will create a new project matching the name of the example, unless overridden (see below). [See here for a full list of starters](https://github.com/stackbit-themes/stackbit-examples). -_Note: This is an experimental feature. Please [report issues](https://github.com/stackbit/create-stackbit-app/issues/new)._ - ### Setting Project Directory Pass a directory name as the only argument when running the command. For example, if you wanted your directory to be name `my-site`, the command would look something like this: diff --git a/config.js b/config.js index 4cfe7c1..f02743e 100644 --- a/config.js +++ b/config.js @@ -1,49 +1,50 @@ const starters = [ { - name: "nextjs", - repoUrl: "https://github.com/stackbit-themes/nextjs-starter", + name: 'nextjs', + repoUrl: 'https://github.com/stackbit-themes/nextjs-starter', }, { - name: "ts-nextjs", - repoUrl: "https://github.com/stackbit-themes/ts-mui-nextjs-starter", + name: 'ts-nextjs', + repoUrl: 'https://github.com/stackbit-themes/ts-mui-nextjs-starter', }, { - name: "contentful", - repoUrl: "https://github.com/stackbit-themes/contentful-starter", - }, - { - name: "full-nextjs", - repoUrl: "https://github.com/stackbit-themes/starter-nextjs-theme", - }, - { - name: "small-biz-nextjs", - repoUrl: "https://github.com/stackbit-themes/small-business-nextjs-theme", - }, - { - name: "personal-nextjs", - repoUrl: "https://github.com/stackbit-themes/personal-nextjs-theme", + name: 'contentful', + repoUrl: 'https://github.com/stackbit-themes/nextjs-contentful-starter', }, ]; const examples = { - repoUrl: "https://github.com/stackbit-themes/stackbit-examples", + repoUrl: 'https://github.com/stackbit-themes/stackbit-examples', directories: [ - "algolia-search", - "angular-contentful", - "chakra-ui", - "cloudinary-contentful", - "hydrogen-contentful-demo-store", - "ninetailed-personalization", - "onboarding-webapp", - "sveltekit-contentful", - "tutorial-nextjs-contentful", - "tutorial-nextjs-files", + 'ab-testing', + 'airtable-content-source', + 'algolia-search', + 'angular-contentful', + 'auto-annotated-portfolio', + 'chakra-ui', + 'cloudinary-contentful', + 'cloudinary-unpic', + 'contentlayer', + 'documentation', + 'gatsby-contentful', + 'hydrogen-contentful-demo-store', + 'i18n-nextjs-contentful', + 'ninetailed-personalization', + 'nuxt3-preview', + 'onboarding-webapp', + 'sveltekit-contentful', + 'tutorial-gatsby-contentful', + 'tutorial-html-contentful', + 'tutorial-html-json', + 'tutorial-nextjs-contentful', + 'tutorial-nextjs-files', + 'unsplash-asset-source', ], }; export default { - defaults: { dirName: "my-stackbit-site", starter: starters[0] }, - minGitVersion: "2.25.0", + defaults: { dirName: 'my-stackbit-site', starter: starters[0] }, + minGitVersion: '2.25.0', examples, starters, }; diff --git a/index.js b/index.js index a75f688..dc5920c 100755 --- a/index.js +++ b/index.js @@ -1,15 +1,15 @@ #!/usr/bin/env node -import chalk from "chalk"; -import { exec } from "child_process"; -import fs from "fs"; -import path from "path"; -import readline from "readline"; -import util from "util"; -import yargs from "yargs"; -import { hideBin } from "yargs/helpers"; +import chalk from 'chalk'; +import { exec } from 'child_process'; +import fs from 'fs-extra'; +import path from 'path'; +import readline from 'readline'; +import util from 'util'; +import yargs from 'yargs'; +import { hideBin } from 'yargs/helpers'; -import config from "./config.js"; +import config from './config.js'; /* --- Helpers --- */ @@ -39,12 +39,9 @@ async function installDependencies(dirName) { async function initGit(dirName) { console.log(`Setting up Git ...`); - await run(`rm -rf ${dirName}/.git`); - await run( - `cd ${dirName} && git init && git add . && git commit -m "New Stackbit project"` - ); + fs.removeSync(`${dirName}/.git`); + await run(`cd ${dirName} && git init && git add . && git commit -m "New Stackbit project"`); } - /** * Given a version string, compare it to a control version. Returns: * @@ -61,7 +58,7 @@ function compareVersion(version, control) { // Return 0 if the versions match. if (version === control) return returnValue; // Break the versions into arrays of integers. - const getVersionParts = (str) => str.split(".").map((v) => parseInt(v)); + const getVersionParts = (str) => str.split('.').map((v) => parseInt(v)); const versionParts = getVersionParts(version); const controlParts = getVersionParts(control); // Loop and compare each item. @@ -78,14 +75,14 @@ function compareVersion(version, control) { /* --- Parse CLI Arguments */ const args = yargs(hideBin(process.argv)) - .option("starter", { - alias: "s", - describe: "Choose a starter", + .option('starter', { + alias: 's', + describe: 'Choose a starter', choices: config.starters.map((s) => s.name), }) - .option("example", { - alias: "e", - describe: "Start from an example", + .option('example', { + alias: 'e', + describe: 'Start from an example', choices: config.examples.directories, }) .help() @@ -93,9 +90,7 @@ const args = yargs(hideBin(process.argv)) /* --- References --- */ -const starter = config.starters.find( - (s) => s.name === (args.starter ?? config.defaults.starter.name) -); +const starter = config.starters.find((s) => s.name === (args.starter ?? config.defaults.starter.name)); // Current time in seconds. const timestamp = Math.round(new Date().getTime() / 1000); @@ -117,7 +112,7 @@ async function cloneStarter() { // Output next steps: console.log(` -๐ŸŽ‰ ${chalk.bold("Welcome to Stackbit!")} ๐ŸŽ‰ +๐ŸŽ‰ ${chalk.bold('Welcome to Stackbit!')} ๐ŸŽ‰ Follow the instructions for getting Started here: @@ -128,23 +123,18 @@ Follow the instructions for getting Started here: /* --- New Project from Example --- */ async function cloneExample() { - const gitResult = await run("git --version"); + const gitResult = await run('git --version'); const gitVersionMatch = gitResult.stdout.match(/\d+\.\d+\.\d+/); if (!gitVersionMatch || !gitVersionMatch[0]) { console.error( `Cannot determine git version, which is required for starting from an example.`, `\nPlease report this:`, - chalk.underline( - "https://github.com/stackbit/create-stackbit-app/issues/new" - ) + chalk.underline('https://github.com/stackbit/create-stackbit-app/issues/new'), ); process.exit(1); } if (compareVersion(gitVersionMatch[0], config.minGitVersion) < 0) { - console.error( - `Starting from an example requires git version ${config.minGitVersion} or later.`, - "Please upgrade" - ); + console.error(`Starting from an example requires git version ${config.minGitVersion} or later.`, 'Please upgrade'); process.exit(1); } @@ -154,29 +144,27 @@ async function cloneExample() { try { // Sparse clone the monorepo. - await run( - `git clone --depth 1 --filter=blob:none --sparse ${config.examples.repoUrl} ${tmpDir}` - ); + await run(`git clone --depth 1 --filter=blob:none --sparse ${config.examples.repoUrl} ${tmpDir}`); // Checkout just the example dir. await run(`cd ${tmpDir} && git sparse-checkout set ${args.example}`); - // Copy out into a new directory within current working directory. - await run(`cp -R ${tmpDir}/${args.example} ${dirName}`); + // move out into a new directory. + fs.moveSync(`${tmpDir}/${args.example}`, dirName); // Delete the clone. - await run(`rm -rf ${tmpDir}`); + fs.removeSync(tmpDir); // Project Setup await installDependencies(dirName); await initGit(dirName); } catch (err) { console.error(err); - if (fs.existsSync(dirName)) await run(`rm -rf ${dirName}`); - if (fs.existsSync(tmpDir)) await run(`rm -rf ${tmpDir}`); + if (fs.existsSync(dirName)) fs.removeSync(dirName); + if (fs.existsSync(tmpDir)) fs.removeSync(tmpDir); process.exit(1); } // Output next steps: console.log(` -๐ŸŽ‰ ${chalk.bold("Your example project is ready!")} ๐ŸŽ‰ +๐ŸŽ‰ ${chalk.bold('Your example project is ready!')} ๐ŸŽ‰ Follow the instructions and learn more about the example here: @@ -190,9 +178,9 @@ async function integrateStackbit() { return new Promise(async (resolve) => { const integrate = await prompt(` This looks like an existing project. - ${chalk.bold("Would you like to install Stackbit in this project?")} [Y/n] `); + ${chalk.bold('Would you like to install Stackbit in this project?')} [Y/n] `); - if (!["yes", "y"].includes(integrate?.toLowerCase())) return resolve(false); + if (!['yes', 'y'].includes(integrate?.toLowerCase())) return resolve(false); console.log(` Visit the following URL to learn more about the integration process: @@ -208,11 +196,11 @@ Visit the following URL to learn more about the integration process: async function doCreate() { // If the current directory has a package.json file, we assume we're in an // active project, and will not create a new project. - const packageJsonFilePath = path.join(process.cwd(), "package.json"); + const packageJsonFilePath = path.join(process.cwd(), 'package.json'); if (fs.existsSync(packageJsonFilePath)) return integrateStackbit(); // If both starter and example were specified, throw an error message. if (args.starter && args.example) { - console.error("[ERROR] Cannot specify a starter and an example."); + console.error('[ERROR] Cannot specify a starter and an example.'); process.exit(1); } // Start from an example if specified. diff --git a/package-lock.json b/package-lock.json index 6c2d87d..7ff3eac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,16 @@ { "name": "create-stackbit-app", - "version": "0.1.9", + "version": "0.2.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "create-stackbit-app", - "version": "0.1.9", + "version": "0.2.2", "license": "MIT", "dependencies": { "chalk": "^5.0.0", + "fs-extra": "^10.1.0", "yargs": "^17.3.1" }, "bin": { @@ -88,6 +89,19 @@ "node": ">=6" } }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -96,6 +110,11 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -104,6 +123,17 @@ "node": ">=8" } }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -136,6 +166,14 @@ "node": ">=8" } }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -238,16 +276,40 @@ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" }, + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -271,6 +333,11 @@ "ansi-regex": "^5.0.1" } }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/package.json b/package.json index 2a5750c..85e33e6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "create-stackbit-app", - "version": "0.1.9", + "version": "0.2.2", "description": "Create a new Stackbit site, or add Stackbit to an existing site.", "main": "index.js", "scripts": { @@ -15,6 +15,7 @@ "type": "module", "dependencies": { "chalk": "^5.0.0", + "fs-extra": "^10.1.0", "yargs": "^17.3.1" } }