UNPKG

prettier-plugin-pkg

Version:

An opinionated package.json formatter plugin for Prettier

483 lines (475 loc) 10.6 kB
'use strict'; var babelParser = require('prettier/plugins/babel.js'); const DEFAULT_LIFECYCLE_SCRIPTS = /* @__PURE__ */ new Set([ "dependencies", "install", "pack", "prepare", "publish", "restart", "shrinkwrap", "start", "stop", "test", "version" ]); function alphabetSort(a, b) { return a > b ? 1 : a < b ? -1 : 0; } const sortObject = (a, b) => alphabetSort(a.key.value, b.key.value); const sortStringArray = (a, b) => alphabetSort(a.value, b.value); const getScriptSortProps = (scriptName, allScriptNames) => { if (DEFAULT_LIFECYCLE_SCRIPTS.has(scriptName)) { return { base: scriptName, order: 0 }; } if (scriptName.length > 3 && scriptName.startsWith("pre")) { const base = scriptName.slice(3); if (allScriptNames.has(base) || DEFAULT_LIFECYCLE_SCRIPTS.has(base)) { return { base, order: -1 }; } } if (scriptName.length > 4 && scriptName.startsWith("post")) { const base = scriptName.slice(4); if (allScriptNames.has(base) || DEFAULT_LIFECYCLE_SCRIPTS.has(base)) { return { base, order: 1 }; } } return { base: scriptName, order: 0 }; }; const sortScriptNames = (scriptNames) => { const scriptNameSet = new Set(scriptNames); scriptNames = [...scriptNameSet]; return scriptNames.sort((a, b) => { const left = getScriptSortProps(a, scriptNameSet); const right = getScriptSortProps(b, scriptNameSet); if (left.base !== right.base) { return alphabetSort(left.base, right.base); } if (left.order !== right.order) { return alphabetSort(left.order, right.order); } return alphabetSort(a, b); }); }; const sortScripts = (props) => { const scriptOrder = Object.fromEntries( sortScriptNames(props.map((prop) => prop.key.value)).map((name, index) => [ name, index ]) ); props.sort( (a, b) => alphabetSort(scriptOrder[a.key.value], scriptOrder[b.key.value]) ); }; const process$1 = (props) => { const filesNode = props.find((prop) => prop.key.value === "files"); if (!filesNode) { return props; } let readme; let license; const filesNodeValue = filesNode.value; const [normals, negations] = filesNodeValue.elements.reduce( (acc, node) => { const value = node.value.toLowerCase(); if (value === "license") { license = node; return acc; } if (value === "readme" || value === "readme.md") { readme = node; return acc; } acc[+value.startsWith("!")].push(node); return acc; }, [[], []] ); normals.sort(sortStringArray); negations.sort(sortStringArray); if (readme) { normals.push(readme); } if (license) { normals.push(license); } filesNodeValue.elements = [...normals, ...negations]; return props; }; const process = (props, key) => { const item = props.find((prop) => prop.key.value === key); if (item) { if ("elements" in item.value) { item.value.elements.sort(sortStringArray); } else if ("properties" in item.value) { if (key === "scripts") { sortScripts(item.value.properties); } else { item.value.properties.sort(sortObject); } } } return props; }; const dependencyNames = [ "bundledDependencies", "peerDependencies", "peerDependenciesMeta", "dependencies", "dependenciesMeta", "optionalDependencies", "devDependencies", "overrides", "resolutions" ]; const NPM_SORTS = [ "$schema", "name", "version", "description", "keywords", "homepage", "bugs", "license", "author", "contributors", "funding", "files", "exports", "main", "browser", "bin", "man", "directories", "repository", "scripts", "config", "dependencies", "devDependencies", "peerDependencies", "peerDependenciesMeta", "bundleDependencies", "optionalDependencies", "overrides", "engines", "os", "cpu", "libc", "devEngines", "private", "publishConfig", "workspaces" ]; const NPM_PLUS_SORTS = [ "$schema", "name", "displayName", "version", "private", "description", "categories", "keywords", "homepage", "bugs", "repository", "funding", "license", "qna", "author", "maintainers", "contributors", "publisher", "sideEffects", "type", "imports", "exports", "main", "svelte", "umd:main", "jsdelivr", "unpkg", "module", "source", "jsnext:main", "browser", "react-native", "types", "typesVersions", "typings", "style", "example", "examplestyle", "assets", "bin", "man", "directories", "files", "workspaces", "binary", "scripts", "betterScripts", "contributes", "activationEvents", "husky", "simple-git-hooks", "pre-commit", "commitlint", "lint-staged", "nano-staged", "config", "nodemonConfig", "browserify", "babel", "browserslist", "xo", "prettier", "eslintConfig", "eslintIgnore", "npmpackagejsonlint", "release", "remarkConfig", "stylelint", "ava", "jest", "mocha", "nyc", "tap", "oclif", "resolutions", "dependencies", "devDependencies", "dependenciesMeta", "peerDependencies", "peerDependenciesMeta", "optionalDependencies", "bundledDependencies", "bundleDependencies", "extensionPack", "extensionDependencies", "flat", "packageManager", "engines", "engineStrict", "volta", "languageName", "os", "cpu", "preferGlobal", "publishConfig", "icon", "badges", "galleryBanner", "preview", "markdown", "pnpm" ]; const primary = [ // schema definition "$schema", // meta "name", "version", "type", "flat", "displayName", "description", "categories", "repository", "homepage", "bugs", "author", "publisher", "maintainers", "contributors", "donate", "funding", "sponsor", "license", "preview", "private", "workspaces", // constraints "languageName", "packageManager", "engines", "cpu", "os", "libc", "devEngines", // entries "man", "bin", "main", "types", "typings", "typesVersions", "module", "imports", "exports", "esnext", "es2020", "esm2020", "fesm2020", "es2015", "esm2015", "fesm2015", "es5", "esm5", "fesm5", "browser", "umd", "jsdelivr", "unpkg", // contents and utils "directories", "files", "keywords", "scripts", "config", // dependencies ...dependencyNames, "publishConfig", "sideEffects", // vscode spec "icon", "badges", "galleryBanner", "activationEvents", "contributes", "markdown", "qna", "extensionPack", "extensionDependencies", "extensionKind" ]; const DEFAULT_SORT_ORDERS = { npm: NPM_SORTS, "npm-plus": NPM_PLUS_SORTS }; const uniqueArray = (arr) => { return [...new Set(arr)]; }; const sort = (props, options) => { let { packageSortOrder, packageSortOrderPreset } = options; const defaultSortOrder = ( // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition packageSortOrderPreset && DEFAULT_SORT_ORDERS[packageSortOrderPreset] || [] ); packageSortOrder = uniqueArray([ ...packageSortOrder != null ? packageSortOrder : [], ...defaultSortOrder, ...primary ]); const others = []; const known = props.filter((prop) => { if (packageSortOrder.includes(prop.key.value)) { return true; } others.push(prop); return false; }); known.sort( (a, b) => alphabetSort( packageSortOrder.indexOf(a.key.value), packageSortOrder.indexOf(b.key.value) ) ); others.sort(sortObject); return [...known, ...others]; }; var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); const PKG_REG = /[/\\]?package\.json$/; const { json: { parse } } = babelParser.parsers; const DEFAULT_SORTS = ["engines", "devEngines", "scripts", ...dependencyNames]; const format = (properties, options) => { const { packageIgnoreSort } = options; let props = ((packageIgnoreSort == null ? void 0 : packageIgnoreSort.length) ? DEFAULT_SORTS.filter((item) => !packageIgnoreSort.includes(item)) : DEFAULT_SORTS).reduce((acc, item) => process(acc, item), sort(properties, options)); props = process$1(props); return props; }; var index = { name: "prettier-plugin-pkg", parsers: { "json-stringify": __spreadProps(__spreadValues({}, babelParser.parsers["json-stringify"]), { parse(text, options) { const { filepath } = options; const ast = parse(text, options); if (PKG_REG.test(filepath)) { ast.node.properties = format( ast.node.properties, options ); } return ast; } }) }, options: { packageSortOrder: { since: "0.21.0", category: "Package", type: "string", array: true, default: [{ value: [] }], description: "An array of property names to sort the package.json properties by." }, packageIgnoreSort: { since: "0.21.0", category: "Package", type: "string", array: true, default: [{ value: [] }], description: "An array of property names to ignore when sorting the package.json properties." }, packageSortOrderPreset: { since: "0.21.1", category: "Package", type: "choice", choices: [ { value: "npm", description: "Sorted according to https://docs.npmjs.com/cli/v11/configuring-npm/package-json." }, { value: "npm-plus", description: "Sorted according to https://github.com/keithamus/sort-package-json/blob/aa6774ad937feb83178c8bc981f08305e1d22b5c/defaultRules.md." } ], description: "A preset for the package.json sort order." } } }; module.exports = index;