UNPKG

@modyqyw/fabric

Version:

Opinionated shareable specifications for git-based JavaScript/TypeScript projects.

867 lines (853 loc) 26 kB
#!/usr/bin/env node 'use strict'; const node_fs = require('node:fs'); const promises = require('node:fs/promises'); const node_path = require('node:path'); const installPkg = require('@antfu/install-pkg'); const prompts = require('@inquirer/prompts'); const promptAdapterInquirer = require('@listr2/prompt-adapter-inquirer'); const commander = require('commander'); const consola = require('consola'); const defu = require('defu'); const tinyglobby = require('tinyglobby'); const listr2 = require('listr2'); const localPkg = require('local-pkg'); const sortObjectKeys = require('sort-object-keys'); const sortPackageJson = require('sort-package-json'); const updateNotifier = require('update-notifier'); function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; } const consola__default = /*#__PURE__*/_interopDefaultCompat(consola); const sortObjectKeys__default = /*#__PURE__*/_interopDefaultCompat(sortObjectKeys); const updateNotifier__default = /*#__PURE__*/_interopDefaultCompat(updateNotifier); const name = "@modyqyw/fabric"; const version = "11.8.1"; const description = "Opinionated shareable specifications for git-based JavaScript/TypeScript projects."; const keywords = [ "fabric", "specification", "config", "front-end", "frontend", "prettier", "biome", "markdownlint", "eslint", "stylelint", "commitlint", "husky", "simple-git-hooks", "lint-staged", "javascript", "typescript", "js", "ts", "react", "rn", "react-native", "taro", "vue", "vue2", "vue3", "uniapp", "uni-app", "css", "scss", "git", "naming" ]; const homepage = "https://github.com/ModyQyW/fabric#readme"; const bugs = { url: "https://github.com/ModyQyW/fabric/issues" }; const repository = { type: "git", url: "git+https://github.com/ModyQyW/fabric.git" }; const funding = [ { type: "individual", url: "https://github.com/ModyQyW/sponsors" }, { type: "tidelift", url: "https://tidelift.com/funding/github/npm/@modyqyw/fabric" } ]; const license = "MIT"; const author = { name: "ModyQyW", email: "wurui.dev@gmail.com", url: "https://modyqyw.top" }; const type = "module"; const exports$1 = { ".": { "import": { types: "./dist/index.d.mts", "default": "./dist/index.mjs" }, require: { types: "./dist/index.d.cts", "default": "./dist/index.cjs" } }, "./biome.json": "./dist/biome.json", "./cli": { "import": { types: "./dist/cli.d.mts", "default": "./dist/cli.mjs" }, require: { types: "./dist/cli.d.cts", "default": "./dist/cli.cjs" } }, "./commitlint": { "import": { types: "./dist/commitlint.d.mts", "default": "./dist/commitlint.mjs" }, require: { types: "./dist/commitlint.d.cts", "default": "./dist/commitlint.cjs" } }, "./eslint": { "import": { types: "./dist/eslint.d.mts", "default": "./dist/eslint.mjs" }, require: { types: "./dist/eslint.d.cts", "default": "./dist/eslint.cjs" } }, "./lint-staged": { "import": { types: "./dist/lint-staged.d.mts", "default": "./dist/lint-staged.mjs" }, require: { types: "./dist/lint-staged.d.cts", "default": "./dist/lint-staged.cjs" } }, "./markdownlint.json": "./dist/markdownlint.json", "./prettier": { "import": { types: "./dist/prettier.d.mts", "default": "./dist/prettier.mjs" }, require: { types: "./dist/prettier.d.cts", "default": "./dist/prettier.cjs" } }, "./simple-git-hooks": { "import": { types: "./dist/simple-git-hooks.d.mts", "default": "./dist/simple-git-hooks.mjs" }, require: { types: "./dist/simple-git-hooks.d.cts", "default": "./dist/simple-git-hooks.cjs" } }, "./stylelint": { "import": { types: "./dist/stylelint.d.mts", "default": "./dist/stylelint.mjs" }, require: { types: "./dist/stylelint.d.cts", "default": "./dist/stylelint.cjs" } } }; const main = "./dist/index.cjs"; const module$1 = "./dist/index.mjs"; const types = "./dist/index.d.ts"; const typesVersions = { "*": { "*": [ "./dist/*", "./dist/cli.d.ts", "./dist/commitlint.d.ts", "./dist/eslint.d.ts", "./dist/index.d.ts", "./dist/lint-staged.d.ts", "./dist/prettier.d.ts", "./dist/simple-git-hooks.d.ts", "./dist/stylelint.d.ts" ] } }; const bin = { mf: "./dist/cli.mjs", "modyqyw-fabric": "./dist/cli.mjs" }; const files = [ "dist" ]; const scripts = { build: "unbuild", depupdate: "taze -fw", dev: "unbuild --stub", "docs:build": "vitepress build docs", "docs:dev": "vitepress dev docs", "docs:preview": "vitepress preview docs", format: "prettier . \"!**/package-lock.json*\" \"!**/yarn.lock\" \"!**/pnpm-lock.yaml\" --ignore-unknown --write --cache --log-level=warn", lint: "conc \"pnpm:lint:eslint\" \"pnpm:lint:markdownlint\" \"pnpm:lint:package\"", "lint:eslint": "eslint . --fix --cache", "lint:markdownlint": "markdownlint . --fix --ignore-path=.gitignore", "lint:package": "pnpm run build && publint && attw --pack .", prepare: "is-ci || simple-git-hooks", prepublishOnly: "pnpm run build", preversion: "git-branch-is main && conc \"pnpm:lint\" \"pnpm:type-check\"", release: "commit-and-tag-version -a", "type-check": "tsc --noEmit" }; const dependencies = { "@antfu/install-pkg": "^1.0.0", "@babel/core": "^7.26.0", "@babel/eslint-parser": "^7.26.5", "@babel/preset-env": "^7.26.0", "@babel/preset-react": "^7.26.3", "@commitlint/cli": "^19.6.1", "@commitlint/config-angular": "^19.7.0", "@commitlint/config-conventional": "^19.6.0", "@commitlint/config-lerna-scopes": "^19.7.0", "@commitlint/config-nx-scopes": "^19.5.0", "@commitlint/config-pnpm-scopes": "^19.5.0", "@commitlint/config-rush-scopes": "^19.5.0", "@commitlint/types": "^19.5.0", "@eslint-react/shared": "^1.23.2", "@eslint/compat": "^1.2.5", "@inquirer/prompts": "^7.2.3", "@listr2/prompt-adapter-inquirer": "^2.0.18", "@next/eslint-plugin-next": "^15.1.4", "@nuxt/eslint-plugin": "^0.7.5", "@typescript-eslint/eslint-plugin": "^8.20.0", "@typescript-eslint/parser": "^8.20.0", "@unocss/eslint-plugin": "^65.4.0", commander: "^13.0.0", consola: "^3.4.0", defu: "^6.1.4", "eslint-config-flat-gitignore": "^1.0.0", "eslint-import-resolver-oxc": "^0.8.0", "eslint-plugin-command": "^2.1.0", "eslint-plugin-import-x": "^4.6.1", "eslint-plugin-jsdoc": "^50.6.1", "eslint-plugin-jsonc": "^2.18.2", "eslint-plugin-markdown": "^5.1.0", "eslint-plugin-n": "^17.15.1", "eslint-plugin-no-barrel-files": "^1.2.0", "eslint-plugin-nuxt": "^4.0.0", "eslint-plugin-package-json": "^0.19.0", "eslint-plugin-perfectionist": "^4.6.0", "eslint-plugin-promise": "^7.2.1", "eslint-plugin-react-dom": "^1.23.2", "eslint-plugin-react-hooks": "^5.1.0", "eslint-plugin-react-hooks-extra": "^1.23.2", "eslint-plugin-react-naming-convention": "^1.23.2", "eslint-plugin-react-native": "^5.0.0", "eslint-plugin-react-perf": "^3.3.3", "eslint-plugin-react-refresh": "^0.4.18", "eslint-plugin-react-web-api": "^1.23.2", "eslint-plugin-react-x": "^1.23.2", "eslint-plugin-regexp": "^2.7.0", "eslint-plugin-tailwindcss": "^3.17.5", "eslint-plugin-toml": "^0.12.0", "eslint-plugin-unicorn": "^56.0.1", "eslint-plugin-unused-imports": "^4.1.4", "eslint-plugin-vue": "^9.32.0", "eslint-plugin-vue-scoped-css": "^2.9.0", "eslint-plugin-yml": "^1.16.0", globals: "^15.14.0", "jsonc-eslint-parser": "^2.4.0", listr2: "^8.2.5", "local-pkg": "^1.0.0", multimatch: "^7.0.0", postcss: "^8.5.0", "postcss-html": "^1.8.0", "postcss-scss": "^4.0.9", "prettier-plugin-curly": "^0.3.1", "prettier-plugin-jsdoc": "^1.3.2", "sort-object-keys": "^1.1.3", "sort-package-json": "^2.13.0", "stylelint-config-html": "^1.1.0", "stylelint-config-recess-order": "^5.1.1", "stylelint-config-recommended": "^14.0.1", "stylelint-config-recommended-scss": "^14.1.0", "stylelint-config-standard": "^36.0.1", "stylelint-config-standard-scss": "^14.0.0", "stylelint-high-performance-animation": "^1.10.0", "stylelint-order": "^6.0.4", "stylelint-plugin-defensive-css": "^1.0.4", "stylelint-plugin-logical-css": "^1.2.1", tinyglobby: "^0.2.10", "toml-eslint-parser": "^0.10.0", typescript: "^5.7.3", "typescript-eslint": "^8.20.0", "update-notifier": "^7.3.1", "vue-eslint-parser": "^9.4.3", "yaml-eslint-parser": "^1.2.3" }; const devDependencies = { "@arethetypeswrong/cli": "^0.17.3", "@biomejs/biome": "^1.9.4", "@inquirer/type": "^3.0.2", "@tsconfig/node20": "^20.1.4", "@types/node": "^22.10.6", "@types/sort-object-keys": "^1.1.3", "@types/update-notifier": "^6.0.8", "commit-and-tag-version": "^12.5.0", concurrently: "^9.1.2", "esbuild-register": "^3.6.0", eslint: "^9.18.0", "git-branch-is": "^4.0.0", "is-ci": "^4.1.0", "lint-staged": "^15.3.0", "markdownlint-cli": "^0.43.0", oxlint: "^0.15.6", prettier: "^3.4.2", publint: "^0.3.2", react: "^19.0.0", "simple-git-hooks": "^2.11.1", stylelint: "^16.13.1", taze: "^18.1.0", unbuild: "^3.3.1", vitepress: "^1.5.0", vue: "^3.5.13" }; const peerDependencies = { "@biomejs/biome": "^1.9.0", eslint: "^9.10.0", postcss: "^8.0.0", prettier: "^3.0.0", react: "^18.0.0", stylelint: "^16.0.0", typescript: "^5.0.0", vue: "^3.0.0" }; const peerDependenciesMeta = { "@biomejs/biome": { optional: true }, eslint: { optional: true }, postcss: { optional: true }, prettier: { optional: true }, react: { optional: true }, stylelint: { optional: true }, typescript: { optional: true }, vue: { optional: true } }; const packageManager = "pnpm@9.15.4"; const engines = { node: "^20.11.0 || >=21.2.0" }; const publishConfig = { access: "public", registry: "https://registry.npmjs.org/" }; const packageJson = { name: name, version: version, description: description, keywords: keywords, homepage: homepage, bugs: bugs, repository: repository, funding: funding, license: license, author: author, type: type, exports: exports$1, main: main, module: module$1, types: types, typesVersions: typesVersions, bin: bin, files: files, scripts: scripts, dependencies: dependencies, devDependencies: devDependencies, peerDependencies: peerDependencies, peerDependenciesMeta: peerDependenciesMeta, packageManager: packageManager, engines: engines, publishConfig: publishConfig }; updateNotifier__default({ pkg: packageJson }).notify(); const program = new commander.Command().name(packageJson.name).description(packageJson.description).version(packageJson.version).argument("[dir]", "dir to setup @modyqyw/fabric", ".").option("--prettier", "setup Prettier").option("--eslint", "setup ESLint").option("--oxlint", "setup oxlint").option("--stylelint", "setup Stylelint").option("--markdownlint", "setup markdownlint").option("--biome", "setup Biome").option("--tsc", "setup tsc").option("--commitlint", "setup commitlint").option("--lint-staged", "setup lint-staged").option("--simple-git-hooks", "setup simple-git-hooks").option("--editor-config", "setup .editorconfig").option("--vscode", "setup .vscode").option("-a, --all", "setup all functions").option("-c, --clean", "clean legacy setup").parse(); const args = program.args; const opts = program.opts(); const dir = args[0] || "."; const cwd = process.cwd(); function resolvePath(...paths) { return node_path.resolve(cwd, dir, ...paths); } const packageJsonPath = resolvePath("package.json"); const packageJsonContent = node_fs.readFileSync(packageJsonPath, "utf8"); const packageJsonObject = JSON.parse(packageJsonContent); const packageJsonEof = "\n"; const packageJsonIndent = " "; const functionOptions = [ { description: "EditorConfig helps maintain consistent coding styles for multiple developers working on the same project across various editors and IDEs.", name: "EditorConfig", path: ".editorconfig", patterns: [".editorconfig"], template: `root = true [*] charset = utf-8 end_of_line = lf indent_size = 2 indent_style = space insert_final_newline = true trim_trailing_whitespace = true [*.md] trim_trailing_whitespace = false `, value: "editorConfig", vscodeRecommendations: ["EditorConfig.EditorConfig"] }, { description: "Prettier is a widely adopted code formatter with good support for JavaScript / TypeScript / JSX / TSX / CSS / SCSS / Vue, and it's my top pick for formatters.", field: "prettier", name: "Prettier", packages: ["prettier"], path: "prettier.config.mjs", patterns: [".prettierrc*", "prettier.config.*"], scripts: { format: 'prettier . "!**/package-lock.json*" "!**/yarn.lock" "!**/pnpm-lock.yaml" --ignore-unknown --write --cache --log-level=warn' }, template: `import { prettier } from '@modyqyw/fabric'; export default prettier(); `, value: "prettier", vscodeRecommendations: ["esbenp.prettier-vscode"], vscodeSettings: { // 指定默认代码格式化器为 Prettier "editor.defaultFormatter": "esbenp.prettier-vscode", // 保存自动格式化 "editor.formatOnSave": true, // 启动 Prettier "prettier.enable": true } }, { description: "ESLint is a widely adopted linter, mainly for script files.", field: "eslintConfig", name: "ESLint", packages: ["eslint"], path: "eslint.config.mjs", patterns: [".eslintrc*", "eslint.config.*"], scripts: { "lint:eslint": "eslint . --fix --cache" }, template: `import { eslint } from '@modyqyw/fabric'; export default eslint(); `, value: "eslint", vscodeRecommendations: ["dbaeumer.vscode-eslint"], vscodeSettings: { // 启用 ESLint 平面配置 "eslint.experimental.useFlatConfig": true, // < 3.0.10 "eslint.useFlatConfig": true, // >= 3.0.10 // ESLint 检查的语言 "eslint.validate": [ "javascript", "javascriptreact", "typescript", "typescriptreact", "vue", "markdown", "json", "jsonc", "yaml", "toml" ], // JavaScript、JSX、TypeScript、TypeScript JSX、Vue、markdown、JSON、JSONC、YAML、TOML 手动保存后 ESLint 自动修复 "[javascript][javascriptreact][typescript][typescriptreact][vue][markdown][json][jsonc][yaml][toml]": { "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit" } } } }, { description: "oxlint is an emerging linter that requires no configuration by default and is mainly used for script files.", name: "oxlint", packages: ["oxlint"], scripts: { "lint:oxlint": "oxlint --fix" }, value: "oxlint" }, { description: "Stylelint is a widely adopted linter, mainly for style files.", field: "stylelint", name: "Stylelint", packages: ["stylelint"], path: "stylelint.config.mjs", patterns: [".stylelintrc*", "stylelint.config.*"], scripts: { "lint:stylelint": 'stylelint "./**/*.{css,scss,vue}" --fix --cache --aei --ignore-path=.gitignore' }, template: `import { stylelint } from '@modyqyw/fabric'; export default stylelint(); `, value: "stylelint", vscodeRecommendations: ["stylelint.vscode-stylelint"], vscodeSettings: { // 禁用内置的 CSS 检查 "css.validate": false, // 禁用内置的 LESS 检查 "less.validate": false, // 禁用内置的 SCSS 检查 "scss.validate": false, // 启用 Stylelint 代码片段的语言 "stylelint.snippet": ["css", "scss", "vue"], // Stylelint 检查的语言 "stylelint.validate": ["css", "scss", "vue"], // CSS、SCSS、Vue 手动保存后 Stylelint 自动修复 "[css][scss][vue]": { "editor.codeActionsOnSave": { "source.fixAll.stylelint": "explicit" } } } }, { description: "markdownlint is the linter for markdown file.", field: "markdownlint", name: "markdownlint", packages: ["markdownlint-cli"], path: ".markdownlint.json", patterns: [".markdowlintrc*", ".markdownlint.*", "markdownlint.config.*"], scripts: { "lint:markdownlint": "markdownlint . --fix --ignore-path=.gitignore" }, template: `{ "$schema": "https://raw.githubusercontent.com/DavidAnson/markdownlint/main/schema/markdownlint-config-schema.json", "extends": "@modyqyw/fabric/markdownlint.json" } `, value: "markdownlint", vscodeRecommendations: ["DavidAnson.vscode-markdownlint"], vscodeSettings: { // markdown 手动保存后 markdownlint 自动修复 "[markdown]": { "editor.codeActionsOnSave": { "source.fixAll.markdownlint": "explicit" } } } }, { description: "Biome is an all-in-one high-performance toolchain for web projects, aimed to provide functionalities to maintain them. It is a performant linter and a fast formatter.", name: "Biome", packages: ["@biomejs/biome"], path: "biome.json", patterns: ["biome.json"], scripts: { check: "@biomejs/biome check --write" }, template: `{ "extends": "@modyqyw/fabric/biome.json" } `, value: "biome", vscodeRecommendations: ["biomejs.biome"], vscodeSettings: { // 手动保存后 Biome 自动修复 "editor.codeActionsOnSave": { "quickfix.biome": "explicit", "source.organizeImports.biome": "explicit" }, // 指定默认代码格式化器为 Biome "editor.defaultFormatter": "biomejs.biome", // 保存自动格式化 "editor.formatOnSave": true } }, { // TODO: support monorepo description: "tsc is the official type checker that comes with TypeScript.", name: "tsc", packages: [ "typescript", localPkg.isPackageExists("vue") ? "vue-tsc" : undefined ].filter(Boolean), scripts: { "type-check": packageJsonObject?.scripts?.["type-check"] ?? (localPkg.isPackageExists("vue") ? "vue-tsc --noEmit" : "tsc --noEmit") }, value: "tsc" }, { description: "commitlint is a widely adopted Git tool that lints commit messages and helps your team adhere to a commit convention.", field: "commitlint", name: "commitlint", packages: ["@commitlint/cli"], path: "commitlint.config.mjs", patterns: [".commitlintrc*", "commitlint.config.*"], template: `import { commitlint } from '@modyqyw/fabric'; export default commitlint(); `, value: "commitlint" }, { description: "lint-staged is a widely adopted Git tool that executes commands against staged git files to prevent erroneous code from entering the repository.", field: "lint-staged", name: "lint-staged", packages: ["lint-staged"], path: "lint-staged.config.mjs", patterns: [".lintstagedrc*", "lint-staged.config.*"], template: `import { lintStaged } from '@modyqyw/fabric'; export default lintStaged(); `, value: "lintStaged" }, { description: "simple-git-hooks is a widely adopted Git tool that helps you manage Git hooks easily.", field: "simple-git-hooks", name: "simple-git-hooks", packages: ["simple-git-hooks", "is-ci", "esbuild-register"], path: ".simple-git-hooks.cjs", patterns: [".simple-git-hooks*", "simple-git-hooks.*"], scripts: { prepare: "is-ci || simple-git-hooks" }, template: `require('esbuild-register'); const { simpleGitHooks } = require('@modyqyw/fabric'); module.exports = simpleGitHooks(); `, value: "simpleGitHooks" } ]; async function getConflictResolution(task) { return await task.prompt(promptAdapterInquirer.ListrInquirerPromptAdapter).run(prompts.select, { choices: [ { name: "Keep Biome and remove other functions", value: "keep" }, { name: "Remove Biome and keep other functions", value: "remove" } ], message: "Biome may conflict with other functions and is recommended to be used separately. What do you want to do?" }); } const tasks = new listr2.Listr([ { rendererOptions: { persistentOutput: true }, task: async (ctx, task) => { ctx.functions = []; let shouldSkip = false; if (opts.all) { const resolution = await getConflictResolution(task); ctx.functions.push( ...functionOptions.filter((o) => { if (resolution === "keep") { return o.name !== "Prettier" && o.name !== "ESLint" && o.name !== "oxlint" && o.name !== "Stylelint"; } return o.name !== "Biome"; }).map((o) => o.name) ); shouldSkip = true; } else { if (opts.biome && (opts.prettier || opts.eslint || opts.oxlint || opts.stylelint)) { const resolution = await getConflictResolution(task); if (resolution === "keep") { opts.prettier = false; opts.eslint = false; opts.oxlint = false; opts.stylelint = false; } else { opts.biome = false; } } for (const o of functionOptions) { if (opts[o.value]) { ctx.functions.push(o.name); shouldSkip = true; } } } if (shouldSkip) { task.output = `${ctx.functions.join(", ")}`; return task.skip(); } const functions = await task.prompt(promptAdapterInquirer.ListrInquirerPromptAdapter).run(prompts.checkbox, { choices: functionOptions, message: "What functions do you want for your project?" }); if (functions.includes("biome") && (functions.includes("prettier") || functions.includes("eslint") || functions.includes("oxlint") || functions.includes("stylelint"))) { const resolution = await getConflictResolution(task); if (resolution === "keep") { functions.splice(functions.indexOf("prettier"), 1); functions.splice(functions.indexOf("eslint"), 1); functions.splice(functions.indexOf("oxlint"), 1); functions.splice(functions.indexOf("stylelint"), 1); } else { functions.splice(functions.indexOf("biome"), 1); } } ctx.functions = functions.map( (f) => functionOptions.find((o) => o.value === f).name ); task.output = `${ctx.functions.join(", ")}`; }, title: "Select functions" }, { rendererOptions: { persistentOutput: true }, task: async (ctx, task) => { if (opts.vscode != null) { ctx.vscode = opts.vscode; task.output = ctx.vscode ? "Yes" : "No"; return task.skip(); } ctx.vscode = await task.prompt(promptAdapterInquirer.ListrInquirerPromptAdapter).run(prompts.confirm, { default: true, message: "Setup .vscode?" }); task.output = ctx.vscode ? "Yes" : "No"; }, title: "Setup .vscode?" }, { task: async (ctx) => { const filtered = functionOptions.filter( (o) => ctx.functions.includes(o.name) ); await Promise.all( filtered.filter((f) => !!f.patterns).flatMap( (f) => tinyglobby.globSync(f.patterns, { dot: true }).map( (f2) => promises.unlink(resolvePath(f2)) ) ) ); if (packageJsonObject) { for (const o of filtered) { if (o.field) delete packageJsonObject[o.field]; } } }, title: "Clean legacy setup" }, { retry: 1, task: async (ctx) => { const promises$1 = []; const filtered = functionOptions.filter( (o) => ctx.functions.includes(o.name) ); const packages = [...new Set(filtered.flatMap((f) => f.packages ?? []))]; const notInstalled = packages.filter( (p) => !(packageJsonObject?.devDependencies?.[p] || packageJsonObject?.dependencies?.[p]) ); if (notInstalled.length > 0) { promises$1.push( installPkg.installPackage(notInstalled, { cwd: node_path.resolve(cwd, dir), dev: true, silent: true }) ); } for (const f of filtered) { if (f.path && f.template) { promises$1.push(promises.writeFile(resolvePath(f.path), f.template)); } if (f.scripts) { packageJsonObject.scripts = { ...packageJsonObject.scripts, ...f.scripts }; } } if (ctx.vscode) { try { node_fs.accessSync(node_path.resolve(".vscode")); } catch { node_fs.mkdirSync(node_path.resolve(".vscode")); } const vscodeRecommendations = filtered.flatMap( (f) => f.vscodeRecommendations ?? [] ); if (vscodeRecommendations.length > 0) { promises$1.push( promises.writeFile( resolvePath(".vscode", "extensions.json"), JSON.stringify( { recommendations: vscodeRecommendations.toSorted( (a, b) => a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase()) ) }, null, packageJsonIndent ) + packageJsonEof ) ); } const vscodeSettings = defu.defu( {}, ...filtered.map((f) => f.vscodeSettings ?? {}) ); if (Object.keys(vscodeSettings).length > 0) { promises$1.push( promises.writeFile( resolvePath(".vscode", "settings.json"), JSON.stringify( sortObjectKeys__default(vscodeSettings), null, packageJsonIndent ) + packageJsonEof ) ); } } promises$1.push( promises.writeFile( packageJsonPath, JSON.stringify( sortPackageJson.sortPackageJson(packageJsonObject), null, packageJsonIndent ) + packageJsonEof ) ); await Promise.all(promises$1); }, title: "Setup" } ]); tasks.run().catch((error) => { consola__default.error(error); throw new Error(error); });