├── test ├── fixtures │ ├── build │ │ ├── ts │ │ │ ├── .eslintignore │ │ │ ├── README.md │ │ │ ├── types.d.ts │ │ │ ├── src │ │ │ │ ├── styles │ │ │ │ │ └── one.css │ │ │ │ ├── two.ts │ │ │ │ └── one.tsx │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── plain │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── src │ │ │ │ └── schemaType.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── valid │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── src │ │ │ │ ├── styles │ │ │ │ │ └── one.css │ │ │ │ ├── two.js │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ └── folder-sanity-json │ │ │ ├── sanity.json │ │ │ └── .gitkeep │ │ │ ├── src │ │ │ └── one.js │ │ │ └── package.json │ ├── verify │ │ ├── plain │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── src │ │ │ │ └── schemaType.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── css-import │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── lib │ │ │ │ ├── styles │ │ │ │ │ └── One.css │ │ │ │ ├── two.js │ │ │ │ └── one.js │ │ │ ├── src │ │ │ │ ├── styles │ │ │ │ │ └── One.css │ │ │ │ ├── two.js │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── css-part │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── lib │ │ │ │ ├── styles │ │ │ │ │ └── one.css │ │ │ │ ├── two.js │ │ │ │ └── one.js │ │ │ ├── src │ │ │ │ ├── styles │ │ │ │ │ └── one.css │ │ │ │ ├── two.js │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── ui-peer-dep │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── sanity.json │ │ │ ├── src │ │ │ │ └── schemaType.js │ │ │ └── package.json │ │ ├── valid-built │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── lib │ │ │ │ ├── styles │ │ │ │ │ └── one.css │ │ │ │ ├── two.js │ │ │ │ └── one.js │ │ │ ├── src │ │ │ │ ├── styles │ │ │ │ │ └── one.css │ │ │ │ ├── two.js │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── css-bad-composes │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── lib │ │ │ │ ├── styles │ │ │ │ │ ├── button.css │ │ │ │ │ └── one.css │ │ │ │ ├── two.js │ │ │ │ └── one.js │ │ │ ├── src │ │ │ │ ├── styles │ │ │ │ │ ├── button.css │ │ │ │ │ └── one.css │ │ │ │ ├── two.js │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── css-bad-import │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── lib │ │ │ │ ├── styles │ │ │ │ │ ├── button.css │ │ │ │ │ └── one.css │ │ │ │ └── one.js │ │ │ ├── src │ │ │ │ ├── styles │ │ │ │ │ ├── button.css │ │ │ │ │ └── one.css │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── css-part-missing │ │ │ ├── LICENSE │ │ │ ├── src │ │ │ │ ├── styles │ │ │ │ │ └── one.css │ │ │ │ ├── two.js │ │ │ │ └── one.js │ │ │ ├── lib │ │ │ │ ├── two.js │ │ │ │ └── one.js │ │ │ ├── README.md │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── css-raw-import │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── lib │ │ │ │ ├── styles │ │ │ │ │ └── One.css │ │ │ │ ├── two.js │ │ │ │ └── one.js │ │ │ ├── src │ │ │ │ ├── styles │ │ │ │ │ └── One.css │ │ │ │ ├── two.js │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── icons-peer-dep │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── sanity.json │ │ │ ├── src │ │ │ │ └── schemaType.js │ │ │ └── package.json │ │ ├── missing-license │ │ │ ├── README.md │ │ │ ├── src │ │ │ │ └── one.js │ │ │ ├── lib │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── non-spdx-license │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── src │ │ │ │ └── one.js │ │ │ ├── lib │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── ui-low-version │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── sanity.json │ │ │ ├── src │ │ │ │ └── schemaType.js │ │ │ └── package.json │ │ ├── useless-files │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── .eslintignore │ │ │ ├── .prettierrc │ │ │ ├── lib │ │ │ │ ├── styles │ │ │ │ │ └── one.css │ │ │ │ ├── two.js │ │ │ │ └── one.js │ │ │ ├── src │ │ │ │ ├── styles │ │ │ │ │ └── one.css │ │ │ │ ├── two.js │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── css-raw-import-missing │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── lib │ │ │ │ ├── styles │ │ │ │ │ └── One.css │ │ │ │ ├── two.js │ │ │ │ └── one.js │ │ │ ├── src │ │ │ │ ├── styles │ │ │ │ │ └── One.css │ │ │ │ ├── two.js │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── invalid-dist-config │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── config.dist.json │ │ │ ├── src │ │ │ │ └── one.js │ │ │ ├── lib │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── missing-license-key │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── src │ │ │ │ └── one.js │ │ │ ├── lib │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── npm-ref-ignored-file │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── types.d.ts │ │ │ ├── src │ │ │ │ └── one.js │ │ │ ├── lib │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── part-ref-ignored-file │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── src │ │ │ │ └── ignored.js │ │ │ ├── lib │ │ │ │ └── ignored.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── valid-kitchen-sink │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── lib │ │ │ │ ├── styles │ │ │ │ │ ├── button.css │ │ │ │ │ ├── customLeaf.css │ │ │ │ │ ├── leaflet │ │ │ │ │ │ ├── markers │ │ │ │ │ │ │ └── marker.css │ │ │ │ │ │ └── leaflet.css │ │ │ │ │ └── one.css │ │ │ │ ├── two.js │ │ │ │ └── one.js │ │ │ ├── src │ │ │ │ ├── styles │ │ │ │ │ ├── button.css │ │ │ │ │ ├── customLeaf.css │ │ │ │ │ ├── leaflet │ │ │ │ │ │ ├── markers │ │ │ │ │ │ │ └── marker.css │ │ │ │ │ │ └── leaflet.css │ │ │ │ │ └── one.css │ │ │ │ ├── two.js │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ └── invalid-dist-config-syntax │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── config.dist.json │ │ │ ├── src │ │ │ └── one.js │ │ │ ├── lib │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ ├── build-npm │ │ ├── folder-package-json │ │ │ ├── package.json │ │ │ │ └── .gitkeep │ │ │ ├── src │ │ │ │ └── one.js │ │ │ └── sanity.json │ │ ├── invalid-package-json │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ └── one.js │ │ │ └── sanity.json │ │ ├── no-package-json │ │ │ ├── src │ │ │ │ └── one.js │ │ │ └── sanity.json │ │ ├── misnamed-package-json │ │ │ ├── src │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── orphaned-package-json │ │ │ ├── src │ │ │ │ └── one.js │ │ │ ├── out │ │ │ │ └── orphan.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── outscoped-package-json │ │ │ ├── src │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── pathless-package-json │ │ │ ├── src │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── sourced-package-json │ │ │ ├── src │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── disallowed-package-json │ │ │ ├── src │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── invalid-package-json-shape │ │ │ ├── src │ │ │ │ └── one.js │ │ │ ├── package.json │ │ │ └── sanity.json │ │ ├── nonstring-main-package-json │ │ │ ├── src │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── targetless-package-json │ │ │ ├── src │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ ├── unprefixed-package-json │ │ │ ├── src │ │ │ │ └── one.js │ │ │ ├── sanity.json │ │ │ └── package.json │ │ └── double-lockfile │ │ │ ├── src │ │ │ ├── styles │ │ │ │ └── one.css │ │ │ ├── two.js │ │ │ └── one.js │ │ │ ├── yarn.lock │ │ │ ├── package-lock.json │ │ │ ├── sanity.json │ │ │ └── package.json │ └── build-sanity │ │ ├── invalid-sanity-json │ │ ├── sanity.json │ │ ├── src │ │ │ ├── styles │ │ │ │ └── one.css │ │ │ ├── two.js │ │ │ └── one.js │ │ └── package.json │ │ ├── no-sanity-json │ │ ├── src │ │ │ └── one.js │ │ └── package.json │ │ ├── nonbool-sanity-json │ │ ├── sanity.json │ │ ├── src │ │ │ ├── styles │ │ │ │ └── one.css │ │ │ ├── two.js │ │ │ └── one.js │ │ └── package.json │ │ ├── nonobject-sanity-json │ │ ├── sanity.json │ │ ├── src │ │ │ ├── styles │ │ │ │ └── one.css │ │ │ ├── two.js │ │ │ └── one.js │ │ └── package.json │ │ ├── disallowed-root-sanity-json │ │ ├── sanity.json │ │ ├── src │ │ │ ├── styles │ │ │ │ └── one.css │ │ │ ├── two.js │ │ │ └── one.js │ │ └── package.json │ │ ├── invalid-sanity-json-shape │ │ ├── sanity.json │ │ ├── src │ │ │ ├── styles │ │ │ │ └── one.css │ │ │ ├── two.js │ │ │ └── one.js │ │ └── package.json │ │ ├── disallowed-sanity-json │ │ ├── src │ │ │ ├── styles │ │ │ │ └── one.css │ │ │ ├── two.js │ │ │ └── one.js │ │ ├── sanity.json │ │ └── package.json │ │ ├── invalid-part-sanity-json │ │ ├── src │ │ │ ├── styles │ │ │ │ └── one.css │ │ │ ├── two.js │ │ │ └── one.js │ │ ├── sanity.json │ │ └── package.json │ │ ├── invalid-part-keys-sanity-json │ │ ├── src │ │ │ ├── styles │ │ │ │ └── one.css │ │ │ ├── two.js │ │ │ └── one.js │ │ ├── package.json │ │ └── sanity.json │ │ ├── nonarray-parts-sanity-json │ │ ├── src │ │ │ ├── styles │ │ │ │ └── one.css │ │ │ ├── two.js │ │ │ └── one.js │ │ ├── sanity.json │ │ └── package.json │ │ ├── nonobject-part-sanity-json │ │ ├── src │ │ │ ├── styles │ │ │ │ └── one.css │ │ │ ├── two.js │ │ │ └── one.js │ │ ├── sanity.json │ │ └── package.json │ │ ├── nonstring-compiled-sanity-json │ │ ├── src │ │ │ ├── styles │ │ │ │ └── one.css │ │ │ ├── two.js │ │ │ └── one.js │ │ ├── sanity.json │ │ └── package.json │ │ ├── nonstring-source-sanity-json │ │ ├── src │ │ │ ├── styles │ │ │ │ └── one.css │ │ │ ├── two.js │ │ │ └── one.js │ │ ├── sanity.json │ │ └── package.json │ │ ├── unprefixed-part-sanity-json │ │ ├── src │ │ │ ├── styles │ │ │ │ └── one.css │ │ │ ├── two.js │ │ │ └── one.js │ │ ├── sanity.json │ │ └── package.json │ │ ├── unprefixed-implementation-sanity-json │ │ ├── src │ │ │ ├── styles │ │ │ │ └── one.css │ │ │ ├── two.js │ │ │ └── one.js │ │ ├── sanity.json │ │ └── package.json │ │ └── dotted-filename-part-sanity-json │ │ ├── src │ │ └── my.schema.js │ │ ├── sanity.json │ │ ├── lib │ │ ├── my.schema.js │ │ └── my.schema.js.map │ │ └── package.json ├── version.test.js ├── cli.test.js ├── build.test.js ├── build-npm.test.js └── build-sanity.test.js ├── src ├── assets │ └── splat │ │ ├── babelrc │ │ ├── prettier.config.js │ │ ├── npmignore │ │ ├── eslint.config.js │ │ ├── editorconfig │ │ ├── gitignore │ │ └── LICENSE ├── configs │ ├── buildExtensions.js │ ├── babelrc.js │ └── uselessFiles.js ├── util │ ├── nullifyError.js │ ├── request.js │ ├── log.js │ ├── prompt.js │ ├── user.js │ ├── readme.js │ └── files.js ├── index.js ├── cmds │ ├── index.js │ ├── verify.js │ ├── version.js │ ├── build.js │ ├── splat.js │ └── init.js ├── sharedFlags.js ├── npm │ ├── publish.js │ ├── resolveLatestVersions.js │ └── manager.js ├── actions │ ├── init.js │ └── build.js ├── dependencies │ └── find.js └── sanity │ └── manifest.js ├── .npmignore ├── babel ├── index.js └── eslint-parser.js ├── .editorconfig ├── .github └── workflows │ └── main.yml ├── .gitignore ├── LICENSE ├── bin └── sanipack.js ├── package.json └── README.md /test/fixtures/build/ts/.eslintignore: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /test/fixtures/build/plain/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/build/plain/README.md: -------------------------------------------------------------------------------- 1 | # some cool 2 | -------------------------------------------------------------------------------- /test/fixtures/build/ts/README.md: -------------------------------------------------------------------------------- 1 | # just a readme 2 | -------------------------------------------------------------------------------- /test/fixtures/build/ts/types.d.ts: -------------------------------------------------------------------------------- 1 | export = string 2 | -------------------------------------------------------------------------------- /test/fixtures/build/valid/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/build/valid/README.md: -------------------------------------------------------------------------------- 1 | # some cool 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/plain/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/plain/README.md: -------------------------------------------------------------------------------- 1 | # some cool 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-import/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-import/README.md: -------------------------------------------------------------------------------- 1 | # some cool 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-part/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-part/README.md: -------------------------------------------------------------------------------- 1 | # some cool 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/ui-peer-dep/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/ui-peer-dep/README.md: -------------------------------------------------------------------------------- 1 | # some cool 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-built/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-built/README.md: -------------------------------------------------------------------------------- 1 | # some cool 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-composes/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-composes/README.md: -------------------------------------------------------------------------------- 1 | # some cool 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-import/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-import/README.md: -------------------------------------------------------------------------------- 1 | # some cool 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-part-missing/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-raw-import/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-raw-import/README.md: -------------------------------------------------------------------------------- 1 | # some cool 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/icons-peer-dep/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/icons-peer-dep/README.md: -------------------------------------------------------------------------------- 1 | # some cool 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/missing-license/README.md: -------------------------------------------------------------------------------- 1 | # so cool 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/non-spdx-license/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/non-spdx-license/README.md: -------------------------------------------------------------------------------- 1 | # so cool 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/ui-low-version/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/ui-low-version/README.md: -------------------------------------------------------------------------------- 1 | # some cool 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/useless-files/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/useless-files/README.md: -------------------------------------------------------------------------------- 1 | # some cool 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-raw-import-missing/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/invalid-dist-config/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/invalid-dist-config/README.md: -------------------------------------------------------------------------------- 1 | # some cool 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/invalid-dist-config/config.dist.json: -------------------------------------------------------------------------------- 1 | [] 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/missing-license-key/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/missing-license-key/README.md: -------------------------------------------------------------------------------- 1 | # so cool 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/npm-ref-ignored-file/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/npm-ref-ignored-file/README.md: -------------------------------------------------------------------------------- 1 | # so cool 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/part-ref-ignored-file/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/part-ref-ignored-file/README.md: -------------------------------------------------------------------------------- 1 | # so cool 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-kitchen-sink/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-kitchen-sink/README.md: -------------------------------------------------------------------------------- 1 | # some cool 2 | -------------------------------------------------------------------------------- /src/assets/splat/babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "sanipack/babel" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build/folder-sanity-json/sanity.json/.gitkeep: -------------------------------------------------------------------------------- 1 | Keep me 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-raw-import-missing/README.md: -------------------------------------------------------------------------------- 1 | # some cool 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/invalid-dist-config-syntax/LICENSE: -------------------------------------------------------------------------------- 1 | some license 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/invalid-dist-config-syntax/README.md: -------------------------------------------------------------------------------- 1 | # some cool 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/npm-ref-ignored-file/types.d.ts: -------------------------------------------------------------------------------- 1 | exports = {} 2 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/folder-package-json/package.json/.gitkeep: -------------------------------------------------------------------------------- 1 | Keep me 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/useless-files/.eslintignore: -------------------------------------------------------------------------------- 1 | some 2 | files 3 | here 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/useless-files/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/invalid-package-json/package.json: -------------------------------------------------------------------------------- 1 | this aint no json 2 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/no-package-json/src/one.js: -------------------------------------------------------------------------------- 1 | export default () => 'one' 2 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/invalid-sanity-json/sanity.json: -------------------------------------------------------------------------------- 1 | This aint no JSON 2 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/no-sanity-json/src/one.js: -------------------------------------------------------------------------------- 1 | export default () => 'one' 2 | -------------------------------------------------------------------------------- /test/fixtures/build/folder-sanity-json/src/one.js: -------------------------------------------------------------------------------- 1 | export default () => 'one' 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/invalid-dist-config-syntax/config.dist.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo" 3 | -------------------------------------------------------------------------------- /test/fixtures/verify/invalid-dist-config/src/one.js: -------------------------------------------------------------------------------- 1 | module.exports = () => null 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/missing-license-key/src/one.js: -------------------------------------------------------------------------------- 1 | module.exports = () => null 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/missing-license/src/one.js: -------------------------------------------------------------------------------- 1 | module.exports = () => null 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/non-spdx-license/src/one.js: -------------------------------------------------------------------------------- 1 | module.exports = () => null 2 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/folder-package-json/src/one.js: -------------------------------------------------------------------------------- 1 | export default () => 'one' 2 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/invalid-package-json/src/one.js: -------------------------------------------------------------------------------- 1 | export default () => 'one' 2 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/misnamed-package-json/src/one.js: -------------------------------------------------------------------------------- 1 | export default () => 'one' 2 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/orphaned-package-json/src/one.js: -------------------------------------------------------------------------------- 1 | export default () => 'one' 2 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/outscoped-package-json/src/one.js: -------------------------------------------------------------------------------- 1 | export default () => 'one' 2 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/pathless-package-json/src/one.js: -------------------------------------------------------------------------------- 1 | export default () => 'one' 2 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/sourced-package-json/src/one.js: -------------------------------------------------------------------------------- 1 | export default () => 'one' 2 | -------------------------------------------------------------------------------- /test/fixtures/build/ts/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/npm-ref-ignored-file/src/one.js: -------------------------------------------------------------------------------- 1 | module.exports = () => null 2 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/disallowed-package-json/src/one.js: -------------------------------------------------------------------------------- 1 | export default () => 'one' 2 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/invalid-package-json-shape/src/one.js: -------------------------------------------------------------------------------- 1 | export default () => 'one' 2 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/nonstring-main-package-json/src/one.js: -------------------------------------------------------------------------------- 1 | export default () => 'one' 2 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/orphaned-package-json/out/orphan.js: -------------------------------------------------------------------------------- 1 | module.exports = 'orphan' 2 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/targetless-package-json/src/one.js: -------------------------------------------------------------------------------- 1 | export default () => 'one' 2 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/unprefixed-package-json/src/one.js: -------------------------------------------------------------------------------- 1 | export default () => 'one' 2 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonbool-sanity-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": null 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonobject-sanity-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": true 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build/valid/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/invalid-dist-config-syntax/src/one.js: -------------------------------------------------------------------------------- 1 | module.exports = () => null 2 | -------------------------------------------------------------------------------- /test/fixtures/verify/part-ref-ignored-file/src/ignored.js: -------------------------------------------------------------------------------- 1 | module.exports = () => null 2 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/disallowed-root-sanity-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-import/lib/styles/One.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-import/src/styles/One.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-part/lib/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-part/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/missing-license/lib/one.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = () => null; -------------------------------------------------------------------------------- /test/fixtures/verify/valid-built/lib/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-built/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-composes/lib/styles/button.css: -------------------------------------------------------------------------------- 1 | .baseButton { 2 | color: #fff; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-composes/src/styles/button.css: -------------------------------------------------------------------------------- 1 | .baseButton { 2 | color: #fff; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-import/lib/styles/button.css: -------------------------------------------------------------------------------- 1 | .baseButton { 2 | color: #fff; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-import/src/styles/button.css: -------------------------------------------------------------------------------- 1 | .baseButton { 2 | color: #fff; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-part-missing/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-raw-import/lib/styles/One.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-raw-import/src/styles/One.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/invalid-dist-config/lib/one.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = () => null; -------------------------------------------------------------------------------- /test/fixtures/verify/missing-license-key/lib/one.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = () => null; -------------------------------------------------------------------------------- /test/fixtures/verify/non-spdx-license/lib/one.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = () => null; -------------------------------------------------------------------------------- /test/fixtures/verify/npm-ref-ignored-file/lib/one.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = () => null; -------------------------------------------------------------------------------- /test/fixtures/verify/useless-files/lib/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/useless-files/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/double-lockfile/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/invalid-sanity-json-shape/sanity.json: -------------------------------------------------------------------------------- 1 | ["json", "but", "not", "an", "object"] 2 | -------------------------------------------------------------------------------- /test/fixtures/build/ts/src/two.ts: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/part-ref-ignored-file/lib/ignored.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = () => null; -------------------------------------------------------------------------------- /test/fixtures/verify/valid-kitchen-sink/lib/styles/button.css: -------------------------------------------------------------------------------- 1 | .baseButton { 2 | color: #fff; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-kitchen-sink/src/styles/button.css: -------------------------------------------------------------------------------- 1 | .baseButton { 2 | color: #fff; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/invalid-sanity-json/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonbool-sanity-json/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build/valid/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-raw-import-missing/lib/styles/One.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-raw-import-missing/src/styles/One.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/invalid-dist-config-syntax/lib/one.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = () => null; -------------------------------------------------------------------------------- /src/configs/buildExtensions.js: -------------------------------------------------------------------------------- 1 | exports.buildExtensions = ['.js', '.jsx', '.es6', '.es', '.mjs', '.ts', '.tsx'] 2 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/disallowed-sanity-json/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/invalid-part-sanity-json/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/invalid-sanity-json-shape/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonobject-sanity-json/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-import/lib/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-import/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-part/lib/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-part/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-built/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-kitchen-sink/lib/styles/customLeaf.css: -------------------------------------------------------------------------------- 1 | :global .leaflet { 2 | height: 100%; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-kitchen-sink/src/styles/customLeaf.css: -------------------------------------------------------------------------------- 1 | :global .leaflet { 2 | height: 100%; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/disallowed-root-sanity-json/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/invalid-part-keys-sanity-json/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonarray-parts-sanity-json/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonobject-part-sanity-json/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonstring-compiled-sanity-json/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonstring-source-sanity-json/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/unprefixed-part-sanity-json/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-composes/lib/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-composes/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-part-missing/lib/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-part-missing/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-raw-import/lib/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-raw-import/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/useless-files/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/double-lockfile/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-raw-import-missing/lib/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-raw-import-missing/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-kitchen-sink/lib/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-kitchen-sink/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/invalid-sanity-json/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonbool-sanity-json/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonobject-sanity-json/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/unprefixed-implementation-sanity-json/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: #bf1942; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/disallowed-sanity-json/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/invalid-part-sanity-json/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/invalid-sanity-json-shape/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonarray-parts-sanity-json/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonobject-part-sanity-json/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-import/lib/styles/one.css: -------------------------------------------------------------------------------- 1 | @import './Button.css'; 2 | 3 | .button { 4 | background: #bf1942; 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-import/src/styles/one.css: -------------------------------------------------------------------------------- 1 | @import './Button.css'; 2 | 3 | .button { 4 | background: #bf1942; 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/invalid-package-json-shape/package.json: -------------------------------------------------------------------------------- 1 | [ 2 | "json", 3 | "but", 4 | "not", 5 | "an", 6 | "object" 7 | ] 8 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/disallowed-root-sanity-json/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/invalid-part-keys-sanity-json/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonstring-compiled-sanity-json/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonstring-source-sanity-json/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/unprefixed-part-sanity-json/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/build/plain/src/schemaType.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'markdown', 3 | title: 'Markdown', 4 | type: 'string', 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/verify/missing-license/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/verify/non-spdx-license/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/verify/invalid-dist-config/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/verify/missing-license-key/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/verify/npm-ref-ignored-file/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/verify/plain/src/schemaType.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'markdown', 3 | title: 'Markdown', 4 | type: 'string', 5 | } 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /.github 2 | /.editorconfig 3 | /.eslintrc 4 | /.gitignore 5 | /.prettierrc 6 | /.taprc 7 | /coverage 8 | /test 9 | .nyc_output 10 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/double-lockfile/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/unprefixed-implementation-sanity-json/src/two.js: -------------------------------------------------------------------------------- 1 | export default function two() { 2 | // do something important 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/verify/invalid-dist-config-syntax/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /babel/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Consumer babel config, eg: 3 | * {"extends": "sanipack/babel"} 4 | */ 5 | module.exports = require('../src/configs/babelrc') 6 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonstring-compiled-sanity-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": true 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonstring-source-sanity-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": {}, 4 | "compiled": "./lib" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-composes/lib/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | composes: baseButton from './baseButton.css'; 3 | background: #bf1942; 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-composes/src/styles/one.css: -------------------------------------------------------------------------------- 1 | .button { 2 | composes: baseButton from './baseButton.css'; 3 | background: #bf1942; 4 | } 5 | -------------------------------------------------------------------------------- /src/assets/splat/prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: false, 3 | printWidth: 100, 4 | bracketSpacing: false, 5 | singleQuote: true, 6 | } 7 | -------------------------------------------------------------------------------- /src/assets/splat/npmignore: -------------------------------------------------------------------------------- 1 | /test 2 | /coverage 3 | .editorconfig 4 | .eslintrc 5 | .gitignore 6 | .github 7 | .prettierrc 8 | .travis.yml 9 | .nyc_output 10 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/double-lockfile/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-double-lockfile", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-kitchen-sink/lib/styles/leaflet/markers/marker.css: -------------------------------------------------------------------------------- 1 | .marker { 2 | composes: baseButton from '../../button.css'; 3 | background: #bf1942; 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-kitchen-sink/src/styles/leaflet/markers/marker.css: -------------------------------------------------------------------------------- 1 | .marker { 2 | composes: baseButton from '../../button.css'; 3 | background: #bf1942; 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/disallowed-sanity-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "api": { 3 | "projectId": "abc123" 4 | }, 5 | "project": { 6 | "displayName": "foo" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/pathless-package-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "parts": [ 3 | { 4 | "name": "part:pathless/some/thing", 5 | "path": "one.js" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonobject-part-sanity-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": ["true"] 8 | } 9 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-part-missing/README.md: -------------------------------------------------------------------------------- 1 | Note how the `src` directory contains the `styles` folder while the `lib` does not. This is what we want to uncover in this fixture. 2 | -------------------------------------------------------------------------------- /test/fixtures/build/plain/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "parts": [ 3 | { 4 | "implements": "part:@sanity/base/schema-type", 5 | "path": "./src/schemaType.js" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /test/fixtures/verify/plain/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "parts": [ 3 | { 4 | "implements": "part:@sanity/base/schema-type", 5 | "path": "./src/schemaType.js" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /src/assets/splat/eslint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: 'sanipack/babel/eslint-parser', 3 | extends: ['sanity', 'sanity/react', 'prettier'], 4 | ignorePatterns: ['lib/**/'], 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/dotted-filename-part-sanity-json/src/my.schema.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'myThing', 3 | type: 'document', 4 | field: [{name: 'title', type: 'string'}], 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/verify/ui-peer-dep/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "parts": [ 3 | { 4 | "implements": "part:@sanity/base/schema-type", 5 | "path": "./src/schemaType.js" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-kitchen-sink/lib/styles/one.css: -------------------------------------------------------------------------------- 1 | @import './leaflet/leaflet.css'; 2 | 3 | .button { 4 | composes: baseButton from './button.css'; 5 | background: #bf1942; 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-kitchen-sink/src/styles/one.css: -------------------------------------------------------------------------------- 1 | @import './leaflet/leaflet.css'; 2 | 3 | .button { 4 | composes: baseButton from './button.css'; 5 | background: #bf1942; 6 | } 7 | -------------------------------------------------------------------------------- /src/util/nullifyError.js: -------------------------------------------------------------------------------- 1 | module.exports = {nullifyError} 2 | 3 | function nullifyError(err) { 4 | if (err instanceof TypeError) { 5 | throw err 6 | } 7 | 8 | return null 9 | } 10 | -------------------------------------------------------------------------------- /test/fixtures/verify/icons-peer-dep/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "parts": [ 3 | { 4 | "implements": "part:@sanity/base/schema-type", 5 | "path": "./src/schemaType.js" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /test/fixtures/verify/ui-low-version/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "parts": [ 3 | { 4 | "implements": "part:@sanity/base/schema-type", 5 | "path": "./src/schemaType.js" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /babel/eslint-parser.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Re-exported eslint parser for consumers, eg (.eslintrc): 3 | * {"parser": "sanipack/babel/eslint-parser"} 4 | */ 5 | module.exports = require('@babel/eslint-parser') 6 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonarray-parts-sanity-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": { 8 | "foo": "bar" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-built/lib/two.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = two; 7 | 8 | function two() {// do something important 9 | } -------------------------------------------------------------------------------- /test/fixtures/verify/useless-files/lib/two.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = two; 7 | 8 | function two() {// do something important 9 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const build = require('./actions/build') 2 | const verify = require('./actions/verify') 3 | const splat = require('./actions/splat') 4 | 5 | module.exports = { 6 | build, 7 | verify, 8 | splat, 9 | } 10 | -------------------------------------------------------------------------------- /src/cmds/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | init: require.resolve('./init'), 3 | build: require.resolve('./build'), 4 | splat: require.resolve('./splat'), 5 | verify: require.resolve('./verify'), 6 | version: require.resolve('./version'), 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/build/ts/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:ts/some/thing", 10 | "path": "one" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/invalid-part-sanity-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": 13, 10 | "path": 14 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build/valid/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:valid/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-import/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:css-part/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/verify/useless-files/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:valid/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-built/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:valid/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/double-lockfile/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:valid/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-import/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:css-part/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-raw-import/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:css-part/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-kitchen-sink/lib/styles/leaflet/leaflet.css: -------------------------------------------------------------------------------- 1 | @import '../customLeaf.css'; 2 | 3 | :global .leaflet { 4 | width: 100%; 5 | } 6 | 7 | .localLeaf { 8 | composes: marker from './markers/marker.css'; 9 | 10 | font-size: 2em; 11 | } 12 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-kitchen-sink/src/styles/leaflet/leaflet.css: -------------------------------------------------------------------------------- 1 | @import '../customLeaf.css'; 2 | 3 | :global .leaflet { 4 | width: 100%; 5 | } 6 | 7 | .localLeaf { 8 | composes: marker from './markers/marker.css'; 9 | 10 | font-size: 2em; 11 | } 12 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-composes/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:css-part/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-kitchen-sink/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:css-part/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | ; editorconfig.org 2 | root = true 3 | charset= utf8 4 | 5 | [*] 6 | end_of_line = lf 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | indent_style = space 10 | indent_size = 2 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /src/sharedFlags.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | debug: { 3 | default: false, 4 | type: 'boolean', 5 | }, 6 | silent: { 7 | type: 'boolean', 8 | default: false, 9 | }, 10 | verbose: { 11 | type: 'boolean', 12 | default: false, 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/no-package-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:no-package-json/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/orphaned-package-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./out" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:orphaned/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/sourced-package-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:sourced/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/unprefixed-part-sanity-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "some-part-name", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-raw-import-missing/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:css-part/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/nonstring-main-package-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:foobar/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/outscoped-package-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:outscoped/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/targetless-package-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:targetless/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /src/npm/publish.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const npmPacklist = require('npm-packlist') 3 | 4 | module.exports = {getPublishableFiles} 5 | 6 | function getPublishableFiles(basePath) { 7 | return npmPacklist({basePath}).then(files => files.map(file => path.normalize(file))) 8 | } 9 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/folder-package-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:folder-package-json/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/invalid-package-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:invalid-package-json/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /src/assets/splat/editorconfig: -------------------------------------------------------------------------------- 1 | ; editorconfig.org 2 | root = true 3 | charset= utf8 4 | 5 | [*] 6 | end_of_line = lf 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | indent_style = space 10 | indent_size = 2 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/disallowed-package-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:invalid-package-json/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/misnamed-package-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:invalid-package-json/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/unprefixed-package-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:invalid-package-json/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/unprefixed-implementation-sanity-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "implements": "some-part-name", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/verify/part-ref-ignored-file/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:part-ref-ignored-file/some/thing", 10 | "path": "ignored.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/invalid-package-json-shape/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:invalid-package-json/some/thing", 10 | "path": "one.js" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/verify/ui-peer-dep/src/schemaType.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {Button} from '@sanity/ui' 3 | 4 | module.exports = { 5 | name: 'button', 6 | title: 'Button', 7 | type: 'string', 8 | inputComponent: () => React.createElement(Button, {text: 'Click me'}), 9 | } 10 | -------------------------------------------------------------------------------- /test/fixtures/verify/icons-peer-dep/src/schemaType.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {Button} from '@sanity/ui' 3 | 4 | module.exports = { 5 | name: 'button', 6 | title: 'Button', 7 | type: 'string', 8 | inputComponent: () => React.createElement(Button, {text: 'Click me'}), 9 | } 10 | -------------------------------------------------------------------------------- /test/fixtures/verify/ui-low-version/src/schemaType.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {Button} from '@sanity/ui' 3 | 4 | module.exports = { 5 | name: 'button', 6 | title: 'Button', 7 | type: 'string', 8 | inputComponent: () => React.createElement(Button, {text: 'Click me'}), 9 | } 10 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/dotted-filename-part-sanity-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "implements": "part:@sanity/base/schema-type", 10 | "path": "my.schema" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build/plain/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-plain", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a fixture", 6 | "main": "./src/schemaType.js", 7 | "keywords": [ 8 | "sanity", 9 | "sanity-plugin" 10 | ], 11 | "author": "Some person", 12 | "license": "MIT" 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/verify/plain/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-plain", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a fixture", 6 | "main": "./src/schemaType.js", 7 | "keywords": [ 8 | "sanity", 9 | "sanity-plugin" 10 | ], 11 | "author": "Some person", 12 | "license": "MIT" 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/misnamed-package-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": 123, 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "Some person", 12 | "license": "ISC" 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-import/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | componentDidMount() { 7 | two() 8 | } 9 | 10 | render() { 11 | return 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-part/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | componentDidMount() { 7 | two() 8 | } 9 | 10 | render() { 11 | return 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-part/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:css-part/some/thing", 10 | "path": "one.js" 11 | }, 12 | { 13 | "name": "part:css-part/some/style", 14 | "path": "styles/one.css" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-composes/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | componentDidMount() { 7 | two() 8 | } 9 | 10 | render() { 11 | return 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-part-missing/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | componentDidMount() { 7 | two() 8 | } 9 | 10 | render() { 11 | return 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-raw-import/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/One.css?raw' 4 | 5 | export default class One extends React.PureComponent { 6 | componentDidMount() { 7 | two() 8 | } 9 | 10 | render() { 11 | return 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-kitchen-sink/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | componentDidMount() { 7 | two() 8 | } 9 | 10 | render() { 11 | return 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/nonstring-main-package-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-foobar", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "", 6 | "main": 123, 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "Some person", 12 | "license": "ISC" 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/unprefixed-package-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "missing-prefix", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "Some person", 12 | "license": "ISC" 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-part-missing/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:css-part/some/thing", 10 | "path": "one.js" 11 | }, 12 | { 13 | "name": "part:css-part/some/style", 14 | "path": "styles/one.css" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/disallowed-package-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "This is not allowed", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "Some person", 12 | "license": "ISC" 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/sourced-package-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-sourced", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "", 6 | "main": "./src/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "Some person", 12 | "license": "ISC" 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-raw-import-missing/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css?raw' 4 | 5 | export default class One extends React.PureComponent { 6 | componentDidMount() { 7 | two() 8 | } 9 | 10 | render() { 11 | return 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/orphaned-package-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-orphaned", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "", 6 | "main": "./out/orphan.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "Some person", 12 | "license": "ISC" 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/outscoped-package-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-outscoped", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "", 6 | "main": "./foo/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "Some person", 12 | "license": "ISC" 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/pathless-package-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-pathless", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "", 6 | "main": "./source/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "Some person", 12 | "license": "ISC" 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/targetless-package-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-targetless", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "", 6 | "main": "./lib/1.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "Some person", 12 | "license": "ISC" 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/no-sanity-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-no-sanity-json", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "", 6 | "main": "src/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "Some person", 12 | "license": "ISC" 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/invalid-sanity-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-invalid-sanity-json", 3 | "version": "1.0.0", 4 | "private": true, 5 | "main": "./src/one.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "sanity", 11 | "sanity-plugin" 12 | ], 13 | "author": "Some person", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonbool-sanity-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-nonbool-sanity-json", 3 | "version": "1.0.0", 4 | "private": true, 5 | "main": "./lib/one.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "sanity", 11 | "sanity-plugin" 12 | ], 13 | "author": "Some person", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/disallowed-sanity-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-disallowed-sanity-json", 3 | "version": "1.0.0", 4 | "private": true, 5 | "main": "./src/one.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "sanity", 11 | "sanity-plugin" 12 | ], 13 | "author": "Some person", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/dotted-filename-part-sanity-json/lib/my.schema.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = void 0; 7 | var _default = { 8 | name: 'myThing', 9 | type: 'document', 10 | field: [{ 11 | name: 'title', 12 | type: 'string' 13 | }] 14 | }; 15 | exports.default = _default; 16 | //# sourceMappingURL=my.schema.js.map -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonobject-sanity-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-nonobject-sanity-json", 3 | "version": "1.0.0", 4 | "private": true, 5 | "main": "./src/one.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "sanity", 11 | "sanity-plugin" 12 | ], 13 | "author": "Some person", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/invalid-part-sanity-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-invalid-part-sanity-json", 3 | "version": "1.0.0", 4 | "private": true, 5 | "main": "./lib/one.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "sanity", 11 | "sanity-plugin" 12 | ], 13 | "author": "Some person", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/verify/missing-license-key/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-missing-license-key", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a fixture", 6 | "main": "./lib/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "sanity", 12 | "sanity-plugin" 13 | ], 14 | "author": "Some person" 15 | } 16 | -------------------------------------------------------------------------------- /src/util/request.js: -------------------------------------------------------------------------------- 1 | const getIt = require('get-it') 2 | const {jsonRequest, jsonResponse, httpErrors, headers, promise} = require('get-it/middleware') 3 | const pkg = require('../../package.json') 4 | 5 | const request = getIt([ 6 | promise({onlyBody: true}), 7 | jsonRequest(), 8 | jsonResponse(), 9 | httpErrors(), 10 | headers({'User-Agent': `${pkg.name}@${pkg.version}`}), 11 | ]) 12 | 13 | module.exports = {request} 14 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/disallowed-root-sanity-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-disallowed-root-sanity-json", 3 | "version": "1.0.0", 4 | "private": true, 5 | "main": "./src/one.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "sanity", 11 | "sanity-plugin" 12 | ], 13 | "author": "Some person", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/invalid-sanity-json-shape/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-invalid-sanity-json-shape", 3 | "version": "1.0.0", 4 | "private": true, 5 | "main": "./lib/one.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "sanity", 11 | "sanity-plugin" 12 | ], 13 | "author": "Some person", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonarray-parts-sanity-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-nonarray-parts-sanity-json", 3 | "version": "1.0.0", 4 | "private": true, 5 | "main": "./lib/one.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "sanity", 11 | "sanity-plugin" 12 | ], 13 | "author": "Some person", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonobject-part-sanity-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-nonobject-part-sanity-json", 3 | "version": "1.0.0", 4 | "private": true, 5 | "main": "./lib/one.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "sanity", 11 | "sanity-plugin" 12 | ], 13 | "author": "Some person", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/unprefixed-part-sanity-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-unprefixed-part-sanity-json", 3 | "version": "1.0.0", 4 | "private": true, 5 | "main": "./lib/one.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "sanity", 11 | "sanity-plugin" 12 | ], 13 | "author": "Some person", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/invalid-part-keys-sanity-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-invalid-part-keys-sanity-json", 3 | "version": "1.0.0", 4 | "private": true, 5 | "main": "./lib/one.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "sanity", 11 | "sanity-plugin" 12 | ], 13 | "author": "Some person", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonstring-source-sanity-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-nonstring-source-sanity-json", 3 | "version": "1.0.0", 4 | "private": true, 5 | "main": "./lib/one.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "sanity", 11 | "sanity-plugin" 12 | ], 13 | "author": "Some person", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonstring-compiled-sanity-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-nonstring-compiled-sanity-json", 3 | "version": "1.0.0", 4 | "private": true, 5 | "main": "./lib/one.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "sanity", 11 | "sanity-plugin" 12 | ], 13 | "author": "Some person", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/verify/missing-license/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-missing-license", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a fixture", 6 | "main": "./lib/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "sanity", 12 | "sanity-plugin" 13 | ], 14 | "author": "Some person", 15 | "license": "MIT" 16 | } 17 | -------------------------------------------------------------------------------- /test/fixtures/verify/ui-peer-dep/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-ui", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a fixture", 6 | "main": "./src/schemaType.js", 7 | "keywords": [ 8 | "sanity", 9 | "sanity-plugin" 10 | ], 11 | "author": "Some person", 12 | "license": "MIT", 13 | "peerDependencies": { 14 | "@sanity/ui": "^0.33.11", 15 | "react": "^17.0.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/dotted-filename-part-sanity-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-unprefixed-part-sanity-json", 3 | "version": "1.0.0", 4 | "private": true, 5 | "main": "./lib/my.schema.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "sanity", 11 | "sanity-plugin" 12 | ], 13 | "author": "Some person", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/invalid-part-keys-sanity-json/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | "source": "./src", 4 | "compiled": "./lib" 5 | }, 6 | 7 | "parts": [ 8 | { 9 | "name": "part:invalid-part-keys-sanity-json/foo/bar", 10 | "path": "one.js" 11 | }, 12 | { 13 | "name": "part:invalid-part-keys-sanity-json/foo/other", 14 | "path": "two.js", 15 | "unknown": "key" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /test/fixtures/verify/icons-peer-dep/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-ui", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a fixture", 6 | "main": "./src/schemaType.js", 7 | "keywords": [ 8 | "sanity", 9 | "sanity-plugin" 10 | ], 11 | "author": "Some person", 12 | "license": "MIT", 13 | "peerDependencies": { 14 | "@sanity/icons": "^1.0.6", 15 | "react": "^17.0.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/fixtures/verify/non-spdx-license/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-non-spdx-license", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a fixture", 6 | "main": "./lib/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "sanity", 12 | "sanity-plugin" 13 | ], 14 | "author": "Some person", 15 | "license": "lol" 16 | } 17 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/unprefixed-implementation-sanity-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-unprefixed-implementation-sanity-json", 3 | "version": "1.0.0", 4 | "private": true, 5 | "main": "./lib/one.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "sanity", 11 | "sanity-plugin" 12 | ], 13 | "author": "Some person", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/verify/invalid-dist-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-invalid-dist-config", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a fixture", 6 | "main": "./lib/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "sanity", 12 | "sanity-plugin" 13 | ], 14 | "author": "Some person", 15 | "license": "MIT" 16 | } 17 | -------------------------------------------------------------------------------- /test/fixtures/build/folder-sanity-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-folder-sanity-json", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just an invalid thing", 6 | "main": "./src/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "sanity", 12 | "sanity-plugin" 13 | ], 14 | "author": "Some person", 15 | "license": "MIT" 16 | } 17 | -------------------------------------------------------------------------------- /test/fixtures/verify/invalid-dist-config-syntax/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-invalid-dist-config", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a fixture", 6 | "main": "./lib/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "sanity", 12 | "sanity-plugin" 13 | ], 14 | "author": "Some person", 15 | "license": "MIT" 16 | } 17 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/dotted-filename-part-sanity-json/lib/my.schema.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../src/my.schema.js"],"names":["name","type","field"],"mappings":";;;;;;eAAe;AACbA,EAAAA,IAAI,EAAE,SADO;AAEbC,EAAAA,IAAI,EAAE,UAFO;AAGbC,EAAAA,KAAK,EAAE,CAAC;AAACF,IAAAA,IAAI,EAAE,OAAP;AAAgBC,IAAAA,IAAI,EAAE;AAAtB,GAAD;AAHM,C","sourcesContent":["export default {\n name: 'myThing',\n type: 'document',\n field: [{name: 'title', type: 'string'}],\n}\n"],"file":"my.schema.js"} -------------------------------------------------------------------------------- /test/fixtures/verify/ui-low-version/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-ui", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a fixture", 6 | "main": "./src/schemaType.js", 7 | "keywords": [ 8 | "sanity", 9 | "sanity-plugin" 10 | ], 11 | "author": "Some person", 12 | "license": "MIT", 13 | "peerDependencies": { 14 | "react": "^17.0.0" 15 | }, 16 | "dependencies": { 17 | "@sanity/ui": "^0.33.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/double-lockfile/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-valid", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a valid Sanity plugin fixture. Do not publish.", 6 | "main": "./lib/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "sanity", 12 | "sanity-plugin" 13 | ], 14 | "author": "Espen Hovlandsdal", 15 | "license": "MIT" 16 | } 17 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-import/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-css-part", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a fixture", 6 | "main": "./lib/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "sanity", 12 | "sanity-plugin" 13 | ], 14 | "peerDependencies": { 15 | "react": "*" 16 | }, 17 | "author": "Some person", 18 | "license": "MIT" 19 | } 20 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-part/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-css-part", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a fixture", 6 | "main": "./lib/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "sanity", 12 | "sanity-plugin" 13 | ], 14 | "peerDependencies": { 15 | "react": "*" 16 | }, 17 | "author": "Some person", 18 | "license": "MIT" 19 | } 20 | -------------------------------------------------------------------------------- /src/configs/babelrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@babel/preset-typescript', 4 | '@babel/preset-react', 5 | [ 6 | '@babel/preset-env', 7 | { 8 | targets: { 9 | node: '10', 10 | chrome: '59', 11 | safari: '10', 12 | firefox: '56', 13 | edge: '14', 14 | }, 15 | modules: 'commonjs', 16 | }, 17 | ], 18 | ], 19 | plugins: ['@babel/plugin-proposal-class-properties'], 20 | } 21 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-composes/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-css-part", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a fixture", 6 | "main": "./lib/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "sanity", 12 | "sanity-plugin" 13 | ], 14 | "peerDependencies": { 15 | "react": "*" 16 | }, 17 | "author": "Some person", 18 | "license": "MIT" 19 | } 20 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-import/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-css-part", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a fixture", 6 | "main": "./lib/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "sanity", 12 | "sanity-plugin" 13 | ], 14 | "peerDependencies": { 15 | "react": "*" 16 | }, 17 | "author": "Some person", 18 | "license": "MIT" 19 | } 20 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-part-missing/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-css-part", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a fixture", 6 | "main": "./lib/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "sanity", 12 | "sanity-plugin" 13 | ], 14 | "peerDependencies": { 15 | "react": "*" 16 | }, 17 | "author": "Some person", 18 | "license": "MIT" 19 | } 20 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-raw-import/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-css-part", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a fixture", 6 | "main": "./lib/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "sanity", 12 | "sanity-plugin" 13 | ], 14 | "peerDependencies": { 15 | "react": "*" 16 | }, 17 | "author": "Some person", 18 | "license": "MIT" 19 | } 20 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-kitchen-sink/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-css-part", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a fixture", 6 | "main": "./lib/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "sanity", 12 | "sanity-plugin" 13 | ], 14 | "peerDependencies": { 15 | "react": "*" 16 | }, 17 | "author": "Some person", 18 | "license": "MIT" 19 | } 20 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-raw-import-missing/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-css-part", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a fixture", 6 | "main": "./lib/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "sanity", 12 | "sanity-plugin" 13 | ], 14 | "peerDependencies": { 15 | "react": "*" 16 | }, 17 | "author": "Some person", 18 | "license": "MIT" 19 | } 20 | -------------------------------------------------------------------------------- /test/fixtures/build/valid/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-valid", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a valid Sanity plugin fixture. Do not publish.", 6 | "main": "./lib/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "sanity", 12 | "sanity-plugin" 13 | ], 14 | "peerDependencies": { 15 | "react": "^16.2.0" 16 | }, 17 | "author": "Some person", 18 | "license": "MIT" 19 | } 20 | -------------------------------------------------------------------------------- /test/fixtures/verify/npm-ref-ignored-file/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-missing-license-key", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a fixture", 6 | "main": "./lib/one.js", 7 | "types": "./types.d.ts", 8 | "files": [ 9 | "lib" 10 | ], 11 | "scripts": { 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "keywords": [ 15 | "sanity", 16 | "sanity-plugin" 17 | ], 18 | "author": "Some person", 19 | "license": "MIT" 20 | } 21 | -------------------------------------------------------------------------------- /test/fixtures/verify/part-ref-ignored-file/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-part-ref-ignored-file", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a fixture", 6 | "main": "./lib/ignored.js", 7 | "files": [ 8 | "lib", 9 | "!lib/ignored.js" 10 | ], 11 | "scripts": { 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "keywords": [ 15 | "sanity", 16 | "sanity-plugin" 17 | ], 18 | "author": "Some person", 19 | "license": "MIT" 20 | } 21 | -------------------------------------------------------------------------------- /test/fixtures/verify/useless-files/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-valid", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a valid Sanity plugin fixture. Do not publish.", 6 | "main": "./lib/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "sanity", 12 | "sanity-plugin" 13 | ], 14 | "peerDependencies": { 15 | "react": "*" 16 | }, 17 | "author": "Some person", 18 | "license": "MIT" 19 | } 20 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-built/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-valid", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a valid Sanity plugin fixture. Do not publish.", 6 | "main": "./lib/one.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "sanity", 12 | "sanity-plugin" 13 | ], 14 | "peerDependencies": { 15 | "react": "^16.2.0" 16 | }, 17 | "author": "Some person", 18 | "license": "MIT" 19 | } 20 | -------------------------------------------------------------------------------- /test/fixtures/build/ts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-ts", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Just a valid typescript Sanity plugin fixture. Do not publish.", 6 | "main": "./lib/one.js", 7 | "types": "types.d.ts", 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "keywords": [ 12 | "sanity", 13 | "sanity-plugin" 14 | ], 15 | "files": [ 16 | "lib", 17 | ".eslintignore" 18 | ], 19 | "author": "Some person", 20 | "license": "MIT" 21 | } 22 | -------------------------------------------------------------------------------- /test/fixtures/build/ts/src/one.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | state = {i: 0} 7 | 8 | handleClick = () => { 9 | this.setState((prev) => ({i: prev.i + 1})) 10 | } 11 | 12 | componentDidMount() { 13 | two() 14 | } 15 | 16 | render() { 17 | const {i} = this.state 18 | return ( 19 | 22 | ) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | - push 4 | - pull_request 5 | jobs: 6 | test: 7 | runs-on: ${{ matrix.platform }} 8 | name: Node.js ${{ matrix.node-version }} / ${{ matrix.platform }} 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | platform: [ubuntu-latest, macos-latest, windows-latest] 13 | node-version: 14 | - 16 15 | - 14 16 | - 12 17 | steps: 18 | - uses: actions/checkout@v2 19 | - uses: actions/setup-node@v1 20 | with: 21 | node-version: ${{ matrix.node-version }} 22 | - run: npm install 23 | - run: npm test 24 | -------------------------------------------------------------------------------- /test/fixtures/build/valid/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | // plugin-proposal-class-properties 7 | state = {i: 0} 8 | 9 | // plugin-proposal-class-properties 10 | handleClick = () => { 11 | this.setState((prev) => ({i: prev.i + 1})) 12 | } 13 | 14 | componentDidMount() { 15 | two() 16 | } 17 | 18 | render() { 19 | const {i} = this.state 20 | return ( 21 | 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/verify/useless-files/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | // plugin-proposal-class-properties 7 | state = {i: 0} 8 | 9 | // plugin-proposal-class-properties 10 | handleClick = () => { 11 | this.setState((prev) => ({i: prev.i + 1})) 12 | } 13 | 14 | componentDidMount() { 15 | two() 16 | } 17 | 18 | render() { 19 | const {i} = this.state 20 | return ( 21 | 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-built/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | // plugin-proposal-class-properties 7 | state = {i: 0} 8 | 9 | // plugin-proposal-class-properties 10 | handleClick = () => { 11 | this.setState((prev) => ({i: prev.i + 1})) 12 | } 13 | 14 | componentDidMount() { 15 | two() 16 | } 17 | 18 | render() { 19 | const {i} = this.state 20 | return ( 21 | 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/build-npm/double-lockfile/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | // plugin-proposal-class-properties 7 | state = {i: 0} 8 | 9 | // plugin-proposal-class-properties 10 | handleClick = () => { 11 | this.setState((prev) => ({i: prev.i + 1})) 12 | } 13 | 14 | componentDidMount() { 15 | two() 16 | } 17 | 18 | render() { 19 | const {i} = this.state 20 | return ( 21 | 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/disallowed-sanity-json/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | // plugin-proposal-class-properties 7 | state = {i: 0} 8 | 9 | // plugin-proposal-class-properties 10 | handleClick = () => { 11 | this.setState((prev) => ({i: prev.i + 1})) 12 | } 13 | 14 | componentDidMount() { 15 | two() 16 | } 17 | 18 | render() { 19 | const {i} = this.state 20 | return ( 21 | 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/invalid-sanity-json/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | // plugin-proposal-class-properties 7 | state = {i: 0} 8 | 9 | // plugin-proposal-class-properties 10 | handleClick = () => { 11 | this.setState((prev) => ({i: prev.i + 1})) 12 | } 13 | 14 | componentDidMount() { 15 | two() 16 | } 17 | 18 | render() { 19 | const {i} = this.state 20 | return ( 21 | 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonbool-sanity-json/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | // plugin-proposal-class-properties 7 | state = {i: 0} 8 | 9 | // plugin-proposal-class-properties 10 | handleClick = () => { 11 | this.setState((prev) => ({i: prev.i + 1})) 12 | } 13 | 14 | componentDidMount() { 15 | two() 16 | } 17 | 18 | render() { 19 | const {i} = this.state 20 | return ( 21 | 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonobject-sanity-json/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | // plugin-proposal-class-properties 7 | state = {i: 0} 8 | 9 | // plugin-proposal-class-properties 10 | handleClick = () => { 11 | this.setState((prev) => ({i: prev.i + 1})) 12 | } 13 | 14 | componentDidMount() { 15 | two() 16 | } 17 | 18 | render() { 19 | const {i} = this.state 20 | return ( 21 | 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/disallowed-root-sanity-json/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | // plugin-proposal-class-properties 7 | state = {i: 0} 8 | 9 | // plugin-proposal-class-properties 10 | handleClick = () => { 11 | this.setState((prev) => ({i: prev.i + 1})) 12 | } 13 | 14 | componentDidMount() { 15 | two() 16 | } 17 | 18 | render() { 19 | const {i} = this.state 20 | return ( 21 | 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/invalid-part-sanity-json/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | // plugin-proposal-class-properties 7 | state = {i: 0} 8 | 9 | // plugin-proposal-class-properties 10 | handleClick = () => { 11 | this.setState((prev) => ({i: prev.i + 1})) 12 | } 13 | 14 | componentDidMount() { 15 | two() 16 | } 17 | 18 | render() { 19 | const {i} = this.state 20 | return ( 21 | 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/invalid-sanity-json-shape/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | // plugin-proposal-class-properties 7 | state = {i: 0} 8 | 9 | // plugin-proposal-class-properties 10 | handleClick = () => { 11 | this.setState((prev) => ({i: prev.i + 1})) 12 | } 13 | 14 | componentDidMount() { 15 | two() 16 | } 17 | 18 | render() { 19 | const {i} = this.state 20 | return ( 21 | 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonarray-parts-sanity-json/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | // plugin-proposal-class-properties 7 | state = {i: 0} 8 | 9 | // plugin-proposal-class-properties 10 | handleClick = () => { 11 | this.setState((prev) => ({i: prev.i + 1})) 12 | } 13 | 14 | componentDidMount() { 15 | two() 16 | } 17 | 18 | render() { 19 | const {i} = this.state 20 | return ( 21 | 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonobject-part-sanity-json/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | // plugin-proposal-class-properties 7 | state = {i: 0} 8 | 9 | // plugin-proposal-class-properties 10 | handleClick = () => { 11 | this.setState((prev) => ({i: prev.i + 1})) 12 | } 13 | 14 | componentDidMount() { 15 | two() 16 | } 17 | 18 | render() { 19 | const {i} = this.state 20 | return ( 21 | 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/unprefixed-part-sanity-json/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | // plugin-proposal-class-properties 7 | state = {i: 0} 8 | 9 | // plugin-proposal-class-properties 10 | handleClick = () => { 11 | this.setState((prev) => ({i: prev.i + 1})) 12 | } 13 | 14 | componentDidMount() { 15 | two() 16 | } 17 | 18 | render() { 19 | const {i} = this.state 20 | return ( 21 | 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/invalid-part-keys-sanity-json/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | // plugin-proposal-class-properties 7 | state = {i: 0} 8 | 9 | // plugin-proposal-class-properties 10 | handleClick = () => { 11 | this.setState((prev) => ({i: prev.i + 1})) 12 | } 13 | 14 | componentDidMount() { 15 | two() 16 | } 17 | 18 | render() { 19 | const {i} = this.state 20 | return ( 21 | 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonstring-compiled-sanity-json/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | // plugin-proposal-class-properties 7 | state = {i: 0} 8 | 9 | // plugin-proposal-class-properties 10 | handleClick = () => { 11 | this.setState((prev) => ({i: prev.i + 1})) 12 | } 13 | 14 | componentDidMount() { 15 | two() 16 | } 17 | 18 | render() { 19 | const {i} = this.state 20 | return ( 21 | 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/nonstring-source-sanity-json/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | // plugin-proposal-class-properties 7 | state = {i: 0} 8 | 9 | // plugin-proposal-class-properties 10 | handleClick = () => { 11 | this.setState((prev) => ({i: prev.i + 1})) 12 | } 13 | 14 | componentDidMount() { 15 | two() 16 | } 17 | 18 | render() { 19 | const {i} = this.state 20 | return ( 21 | 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/build-sanity/unprefixed-implementation-sanity-json/src/one.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import two from './two' 3 | import styles from './styles/one.css' 4 | 5 | export default class One extends React.PureComponent { 6 | // plugin-proposal-class-properties 7 | state = {i: 0} 8 | 9 | // plugin-proposal-class-properties 10 | handleClick = () => { 11 | this.setState((prev) => ({i: prev.i + 1})) 12 | } 13 | 14 | componentDidMount() { 15 | two() 16 | } 17 | 18 | render() { 19 | const {i} = this.state 20 | return ( 21 | 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-import/lib/one.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true, 5 | }) 6 | exports.default = void 0 7 | 8 | var _react = _interopRequireDefault(require('react')) 9 | 10 | var _one = _interopRequireDefault(require('./styles/one.css')) 11 | 12 | function _interopRequireDefault(obj) { 13 | return obj && obj.__esModule ? obj : {default: obj} 14 | } 15 | 16 | class One extends _react.default.PureComponent { 17 | render() { 18 | return /*#__PURE__*/ _react.default.createElement( 19 | 'button', 20 | { 21 | className: _one.default.button, 22 | }, 23 | 'Click me' 24 | ) 25 | } 26 | } 27 | 28 | exports.default = One 29 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-import/src/one.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true, 5 | }) 6 | exports.default = void 0 7 | 8 | var _react = _interopRequireDefault(require('react')) 9 | 10 | var _one = _interopRequireDefault(require('./styles/one.css')) 11 | 12 | function _interopRequireDefault(obj) { 13 | return obj && obj.__esModule ? obj : {default: obj} 14 | } 15 | 16 | class One extends _react.default.PureComponent { 17 | render() { 18 | return /*#__PURE__*/ _react.default.createElement( 19 | 'button', 20 | { 21 | className: _one.default.button, 22 | }, 23 | 'Click me' 24 | ) 25 | } 26 | } 27 | 28 | exports.default = One 29 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-import/lib/one.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = void 0; 7 | 8 | var _react = _interopRequireDefault(require("react")); 9 | 10 | var _two = _interopRequireDefault(require("./two")); 11 | 12 | var _one = _interopRequireDefault(require("./styles/one.css")); 13 | 14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 15 | 16 | class One extends _react.default.PureComponent { 17 | componentDidMount() { 18 | (0, _two.default)(); 19 | } 20 | 21 | render() { 22 | return /*#__PURE__*/_react.default.createElement("button", { 23 | className: _one.default.button 24 | }, 'Click me'); 25 | } 26 | 27 | } 28 | 29 | exports.default = One; 30 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-part/lib/one.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = void 0; 7 | 8 | var _react = _interopRequireDefault(require("react")); 9 | 10 | var _two = _interopRequireDefault(require("./two")); 11 | 12 | var _one = _interopRequireDefault(require("./styles/one.css")); 13 | 14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 15 | 16 | class One extends _react.default.PureComponent { 17 | componentDidMount() { 18 | (0, _two.default)(); 19 | } 20 | 21 | render() { 22 | return /*#__PURE__*/_react.default.createElement("button", { 23 | className: _one.default.button 24 | }, 'Click me'); 25 | } 26 | 27 | } 28 | 29 | exports.default = One; 30 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-bad-composes/lib/one.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = void 0; 7 | 8 | var _react = _interopRequireDefault(require("react")); 9 | 10 | var _two = _interopRequireDefault(require("./two")); 11 | 12 | var _one = _interopRequireDefault(require("./styles/one.css")); 13 | 14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 15 | 16 | class One extends _react.default.PureComponent { 17 | componentDidMount() { 18 | (0, _two.default)(); 19 | } 20 | 21 | render() { 22 | return /*#__PURE__*/_react.default.createElement("button", { 23 | className: _one.default.button 24 | }, 'Click me'); 25 | } 26 | 27 | } 28 | 29 | exports.default = One; 30 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-part-missing/lib/one.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = void 0; 7 | 8 | var _react = _interopRequireDefault(require("react")); 9 | 10 | var _two = _interopRequireDefault(require("./two")); 11 | 12 | var _one = _interopRequireDefault(require("./styles/one.css")); 13 | 14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 15 | 16 | class One extends _react.default.PureComponent { 17 | componentDidMount() { 18 | (0, _two.default)(); 19 | } 20 | 21 | render() { 22 | return /*#__PURE__*/_react.default.createElement("button", { 23 | className: _one.default.button 24 | }, 'Click me'); 25 | } 26 | 27 | } 28 | 29 | exports.default = One; 30 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-kitchen-sink/lib/one.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = void 0; 7 | 8 | var _react = _interopRequireDefault(require("react")); 9 | 10 | var _two = _interopRequireDefault(require("./two")); 11 | 12 | var _one = _interopRequireDefault(require("./styles/one.css")); 13 | 14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 15 | 16 | class One extends _react.default.PureComponent { 17 | componentDidMount() { 18 | (0, _two.default)(); 19 | } 20 | 21 | render() { 22 | return /*#__PURE__*/_react.default.createElement("button", { 23 | className: _one.default.button 24 | }, 'Click me'); 25 | } 26 | 27 | } 28 | 29 | exports.default = One; 30 | -------------------------------------------------------------------------------- /src/configs/uselessFiles.js: -------------------------------------------------------------------------------- 1 | // USELESS IN THE CONTEXT OF A _PUBLISHED_ PACKAGE, OK!!?!?! 2 | // THEY'RE NOT USELESS. PLEASE DONT TAKE OFFENSE, 3 | // I LOVE ALL YOUR ESLINT CONFIGS, CODE COVERAGE AND WHATNOT <3 4 | exports.uselessFiles = [ 5 | '.babel.config.js', 6 | '.babelrc', 7 | '.drone.yml', 8 | '.editorconfig', 9 | '.eslintignore', 10 | '.eslintrc-ts.js', 11 | '.eslintrc-ts', 12 | '.eslintrc', 13 | '.gitignore', 14 | '.github', 15 | '.nyc_output', 16 | '.prettierrc', 17 | '.stylelintignore', 18 | '.stylelintrc.json', 19 | '.stylelintrc', 20 | '.travis.yaml', 21 | '.travis.yml', 22 | 'babel.config.js', 23 | 'coverage', 24 | 'gulpfile.js', 25 | 'lcov-report', 26 | 'lerna.json', 27 | 'now.json', 28 | 'vercel.json', 29 | 'netlify.toml', 30 | 'postcss.config.js', 31 | 'tsconfig.json', 32 | ] 33 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-raw-import/lib/one.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true, 5 | }) 6 | exports.default = void 0 7 | 8 | var _react = _interopRequireDefault(require('react')) 9 | 10 | var _two = _interopRequireDefault(require('./two')) 11 | 12 | var _one = _interopRequireDefault(require('./styles/One.css?raw')) 13 | 14 | function _interopRequireDefault(obj) { 15 | return obj && obj.__esModule ? obj : {default: obj} 16 | } 17 | 18 | class One extends _react.default.PureComponent { 19 | componentDidMount() { 20 | ;(0, _two.default)() 21 | } 22 | 23 | render() { 24 | return /*#__PURE__*/ _react.default.createElement( 25 | 'button', 26 | { 27 | className: _one.default.button, 28 | }, 29 | 'Click me' 30 | ) 31 | } 32 | } 33 | 34 | exports.default = One 35 | -------------------------------------------------------------------------------- /test/fixtures/verify/css-raw-import-missing/lib/one.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true, 5 | }) 6 | exports.default = void 0 7 | 8 | var _react = _interopRequireDefault(require('react')) 9 | 10 | var _two = _interopRequireDefault(require('./two')) 11 | 12 | var _one = _interopRequireDefault(require('./styles/one.css?raw')) 13 | 14 | function _interopRequireDefault(obj) { 15 | return obj && obj.__esModule ? obj : {default: obj} 16 | } 17 | 18 | class One extends _react.default.PureComponent { 19 | componentDidMount() { 20 | ;(0, _two.default)() 21 | } 22 | 23 | render() { 24 | return /*#__PURE__*/ _react.default.createElement( 25 | 'button', 26 | { 27 | className: _one.default.button, 28 | }, 29 | 'Click me' 30 | ) 31 | } 32 | } 33 | 34 | exports.default = One 35 | -------------------------------------------------------------------------------- /src/npm/resolveLatestVersions.js: -------------------------------------------------------------------------------- 1 | const pProps = require('p-props') 2 | const getLatestVersion = require('get-latest-version') 3 | 4 | // We may want to lock certain dependencies to specific versions 5 | const lockedDependencies = { 6 | eslint: '^7.0.0', // Because eslint-plugin-react does not work with v8 yet 7 | } 8 | 9 | module.exports = {resolveLatestVersions} 10 | 11 | function resolveLatestVersions(packages) { 12 | const versions = {} 13 | for (const pkgName of packages) { 14 | versions[pkgName] = pkgName in lockedDependencies ? lockedDependencies[pkgName] : 'latest' 15 | } 16 | 17 | return pProps( 18 | versions, 19 | async (range, pkgName) => { 20 | const version = await getLatestVersion(pkgName, {range}) 21 | return rangeify(version) 22 | }, 23 | {concurrency: 8} 24 | ) 25 | } 26 | 27 | function rangeify(version) { 28 | return `^${version}` 29 | } 30 | -------------------------------------------------------------------------------- /src/assets/splat/gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | # macOS finder cache file 40 | .DS_Store 41 | 42 | # VS Code settings 43 | .vscode 44 | 45 | # Lockfiles 46 | yarn.lock 47 | package-lock.json 48 | 49 | # Cache 50 | .cache 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | # macOS finder cache file 40 | .DS_Store 41 | 42 | # VS Code settings 43 | .vscode 44 | 45 | # Lockfiles 46 | /yarn.lock 47 | /package-lock.json 48 | 49 | # Cache 50 | .cache 51 | 52 | # Fixtures for tests, but only for the `build` command - 53 | # we expect `verify` to have precompiled results to verify 54 | test/fixtures/build/lib 55 | -------------------------------------------------------------------------------- /src/cmds/verify.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const meow = require('meow') 3 | const pkg = require('../../package.json') 4 | const verify = require('../actions/verify') 5 | const sharedFlags = require('../sharedFlags') 6 | 7 | const description = `Verify that a Sanity plugin is ready for publishing` 8 | 9 | const help = ` 10 | Usage 11 | $ ${pkg.binname} verify [] 12 | 13 | Examples 14 | # Verify the plugin in the current directory 15 | $ ${pkg.binname} verify 16 | 17 | # Verify the plugin in ~/my-plugin 18 | $ ${pkg.binname} verify ~/my-plugin 19 | 20 | # Allow package.json to reference files inside the uncompiled source folder 21 | $ ${pkg.binname} verify --allow-source-target 22 | ` 23 | 24 | const flags = { 25 | ...sharedFlags, 26 | allowSourceTarget: { 27 | type: 'boolean', 28 | default: false, 29 | }, 30 | } 31 | 32 | function run({argv}) { 33 | const cli = meow(help, {flags, argv, description}) 34 | const basePath = path.resolve(cli.input[0] || process.cwd()) 35 | return verify({basePath, flags: cli.flags}) 36 | } 37 | 38 | module.exports = run 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Espen Hovlandsdal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/assets/splat/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Espen Hovlandsdal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/npm/manager.js: -------------------------------------------------------------------------------- 1 | const execa = require('execa') 2 | const {prompt} = require('../util/prompt') 3 | 4 | function npmIsAvailable() { 5 | return execa('npm', ['-v']) 6 | .then(() => true) 7 | .catch(() => false) 8 | } 9 | 10 | function yarnIsAvailable() { 11 | return execa('yarn', ['-v']) 12 | .then(() => true) 13 | .catch(() => false) 14 | } 15 | 16 | function pnpmAvailable() { 17 | return execa('pnpm', ['-v']) 18 | .then(() => true) 19 | .catch(() => false) 20 | } 21 | 22 | async function promptForPackageManager() { 23 | const [npm, yarn, pnpm] = await Promise.all([ 24 | npmIsAvailable(), 25 | yarnIsAvailable(), 26 | pnpmAvailable(), 27 | ]) 28 | 29 | const choices = [npm && 'npm', yarn && 'yarn', pnpm && 'pnpm'].filter(Boolean) 30 | if (choices.length < 2) { 31 | return choices[0] || 'npm' 32 | } 33 | 34 | return prompt('Which package manager do you prefer?', { 35 | choices: choices.map((value) => ({value, name: value})), 36 | default: choices[0], 37 | }) 38 | } 39 | 40 | async function installDependencies(pm, {cwd}) { 41 | const proc = execa(pm, ['install'], {cwd, stdio: 'inherit'}) 42 | const {exitCode} = await proc 43 | return exitCode <= 0 44 | } 45 | 46 | module.exports = { 47 | promptForPackageManager, 48 | installDependencies, 49 | } 50 | -------------------------------------------------------------------------------- /test/fixtures/verify/valid-built/lib/one.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = void 0; 7 | 8 | var _react = _interopRequireDefault(require("react")); 9 | 10 | var _two = _interopRequireDefault(require("./two")); 11 | 12 | var _one = _interopRequireDefault(require("./styles/one.css")); 13 | 14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 15 | 16 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 17 | 18 | class One extends _react.default.PureComponent { 19 | constructor() { 20 | super(...arguments); 21 | 22 | _defineProperty(this, "state", { 23 | i: 0 24 | }); 25 | 26 | _defineProperty(this, "handleClick", () => { 27 | this.setState(prev => ({ 28 | i: prev.i + 1 29 | })); 30 | }); 31 | } 32 | 33 | componentDidMount() { 34 | (0, _two.default)(); 35 | } 36 | 37 | render() { 38 | var i = this.state.i; 39 | return /*#__PURE__*/_react.default.createElement("button", { 40 | className: _one.default.button, 41 | onClick: this.handleClick 42 | }, i % 0 === 0 ? 'Foo!' : 'Bar!'); 43 | } 44 | 45 | } 46 | 47 | exports.default = One; -------------------------------------------------------------------------------- /test/fixtures/verify/useless-files/lib/one.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = void 0; 7 | 8 | var _react = _interopRequireDefault(require("react")); 9 | 10 | var _two = _interopRequireDefault(require("./two")); 11 | 12 | var _one = _interopRequireDefault(require("./styles/one.css")); 13 | 14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 15 | 16 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 17 | 18 | class One extends _react.default.PureComponent { 19 | constructor() { 20 | super(...arguments); 21 | 22 | _defineProperty(this, "state", { 23 | i: 0 24 | }); 25 | 26 | _defineProperty(this, "handleClick", () => { 27 | this.setState(prev => ({ 28 | i: prev.i + 1 29 | })); 30 | }); 31 | } 32 | 33 | componentDidMount() { 34 | (0, _two.default)(); 35 | } 36 | 37 | render() { 38 | var i = this.state.i; 39 | return /*#__PURE__*/_react.default.createElement("button", { 40 | className: _one.default.button, 41 | onClick: this.handleClick 42 | }, i % 0 === 0 ? 'Foo!' : 'Bar!'); 43 | } 44 | 45 | } 46 | 47 | exports.default = One; -------------------------------------------------------------------------------- /src/util/log.js: -------------------------------------------------------------------------------- 1 | // Note: This is _specifically_ meant for CLI usage, 2 | // I realize that "singletons" are bad. 3 | 4 | const chalk = require('chalk') 5 | 6 | let beQuiet = false 7 | let beVerbose = false 8 | 9 | function setVerbosity({verbose, silent}) { 10 | if (silent) { 11 | beVerbose = false 12 | beQuiet = true 13 | } else if (verbose) { 14 | beVerbose = true 15 | beQuiet = false 16 | } 17 | } 18 | 19 | module.exports = { 20 | setVerbosity: setVerbosity, 21 | 22 | // Bypasses any checks, prints regardless (only use for things like `cli --version`) 23 | msg: (msg, ...args) => !beQuiet && console.log(msg, ...args), 24 | 25 | // Debug only printed on --verbose 26 | debug: (msg, ...args) => 27 | !beQuiet && beVerbose && console.debug(`${chalk.bgBlack.white('[debug]')} ${msg}`, ...args), 28 | 29 | // Success messages only printed if not --silent 30 | success: (msg, ...args) => 31 | !beQuiet && console.info(`${chalk.bgBlack.greenBright('[success]')} ${msg}`, ...args), 32 | 33 | // Info only printed if not --silent ("standard" level) 34 | info: (msg, ...args) => 35 | !beQuiet && console.info(`${chalk.bgBlack.cyanBright('[info]')} ${msg}`, ...args), 36 | 37 | // Warning only printed if not --silent 38 | warn: (msg, ...args) => 39 | !beQuiet && console.warn(`${chalk.bgBlack.yellowBright('[warn]')} ${msg}`, ...args), 40 | 41 | // Errors are always printed 42 | error: (msg, ...args) => console.error(`${chalk.bgBlack.redBright('[error]')} ${msg}`, ...args), 43 | } 44 | -------------------------------------------------------------------------------- /src/cmds/version.js: -------------------------------------------------------------------------------- 1 | const meow = require('meow') 2 | const pkg = require('../../package.json') 3 | const log = require('../util/log') 4 | const sharedFlags = require('../sharedFlags') 5 | 6 | const description = `Show the installed version of ${pkg.name}` 7 | 8 | const help = ` 9 | Usage 10 | $ ${pkg.binname} version 11 | 12 | Options 13 | --major Show only the major version 14 | --minor Show only the minor version 15 | --patch Show only the patch version 16 | 17 | Examples 18 | $ ${pkg.binname} version 19 | ${pkg.name} version ${pkg.version} 20 | 21 | $ ${pkg.binname} version --major 22 | ${pkg.version.split('.')[0]} 23 | ` 24 | 25 | const flags = { 26 | ...sharedFlags, 27 | 28 | major: { 29 | type: 'boolean', 30 | default: false, 31 | }, 32 | 33 | minor: { 34 | type: 'boolean', 35 | default: false, 36 | }, 37 | 38 | patch: { 39 | type: 'boolean', 40 | default: false, 41 | }, 42 | } 43 | 44 | function run({argv}) { 45 | const cli = meow(help, {flags, argv, description}) 46 | const versionParts = pkg.version.split('.') 47 | const versionNames = ['major', 'minor', 'patch'] 48 | const versionFlags = versionNames.filter((flagName) => cli.flags[flagName]) 49 | const versionFlag = versionFlags[0] 50 | const numVersionFlags = versionFlags.length 51 | 52 | if (numVersionFlags === 0) { 53 | log.msg(`${pkg.name} version ${pkg.version}`) 54 | return 55 | } 56 | 57 | if (numVersionFlags > 1) { 58 | throw new Error( 59 | `--major, --minor and --patch are mutually exclusive - only one can be used at a time` 60 | ) 61 | } 62 | 63 | const partIndex = versionNames.indexOf(versionFlag) 64 | log.msg(versionParts[partIndex]) 65 | } 66 | 67 | module.exports = run 68 | -------------------------------------------------------------------------------- /test/version.test.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const execa = require('execa') 3 | const tap = require('tap') 4 | const pkg = require('../package.json') 5 | 6 | const sanipack = path.resolve(__dirname, '..', pkg.bin.sanipack) 7 | 8 | tap.test('shows full version if no flag is given', async (t) => { 9 | const {stdout, stderr, exitCode} = await execa(sanipack, ['version'], {reject: false}) 10 | t.equal(exitCode, 0, 'should have exit code 0') 11 | t.equal(stderr, '', 'stderr should be empty') 12 | t.equal(stdout, `${pkg.name} version ${pkg.version}`) 13 | }) 14 | 15 | tap.test('shows major version if --major is given', async (t) => { 16 | const {stdout, stderr, exitCode} = await execa(sanipack, ['version', '--major'], {reject: false}) 17 | t.equal(exitCode, 0, 'should have exit code 0') 18 | t.equal(stderr, '', 'stderr should be empty') 19 | t.equal(stdout, pkg.version.split('.')[0]) 20 | }) 21 | 22 | tap.test('shows minor version if --minor is given', async (t) => { 23 | const {stdout, stderr, exitCode} = await execa(sanipack, ['version', '--minor'], {reject: false}) 24 | t.equal(exitCode, 0, 'should have exit code 0') 25 | t.equal(stderr, '', 'stderr should be empty') 26 | t.equal(stdout, pkg.version.split('.')[1]) 27 | }) 28 | 29 | tap.test('shows patch version if --patch is given', async (t) => { 30 | const {stdout, stderr, exitCode} = await execa(sanipack, ['version', '--patch'], {reject: false}) 31 | t.equal(exitCode, 0, 'should have exit code 0') 32 | t.equal(stderr, '', 'stderr should be empty') 33 | t.equal(stdout, pkg.version.split('.')[2]) 34 | }) 35 | 36 | tap.test('throws if two version flags are given', async (t) => { 37 | const {stdout, stderr, exitCode} = await execa(sanipack, ['version', '--major', '--minor'], { 38 | reject: false, 39 | }) 40 | t.equal(exitCode, 1, 'exit code should be 1') 41 | t.equal(stdout, '', 'stdout should be empty') 42 | t.match(stderr, 'only one can be used at a time') 43 | }) 44 | -------------------------------------------------------------------------------- /src/util/prompt.js: -------------------------------------------------------------------------------- 1 | const {URL} = require('url') 2 | const path = require('path') 3 | const inquirer = require('inquirer') 4 | const validNpmName = require('validate-npm-package-name') 5 | const githubUrlToObject = require('github-url-to-object') 6 | 7 | module.exports = {prompt, promptForPackageName, promptForRepoOrigin} 8 | 9 | async function prompt(message, options = {}) { 10 | const type = options.choices ? 'list' : options.type 11 | const result = await inquirer.prompt([{...options, type, message, name: 'single'}]) 12 | return result && result.single 13 | } 14 | 15 | prompt.separator = () => new inquirer.Separator() 16 | 17 | function promptForPackageName({basePath}, defaultVal) { 18 | return prompt('Plugin name (sanity-plugin-...)', { 19 | default: defaultVal || path.basename(basePath), 20 | filter: (name) => { 21 | const prefixless = name.trim().replace(/^sanity-plugin-/, '') 22 | return name[0] === '@' ? name : `sanity-plugin-${prefixless}` 23 | }, 24 | validate: (name) => { 25 | const valid = validNpmName(name) 26 | if (valid.errors) { 27 | return valid.errors[0] 28 | } 29 | 30 | if (name[0] !== '@' && name.endsWith('plugin')) { 31 | return `Name shouldn't include "plugin" multiple times (${name})` 32 | } 33 | 34 | return true 35 | }, 36 | }) 37 | } 38 | 39 | function promptForRepoOrigin(options, defaultVal) { 40 | return prompt('Git repository URL', { 41 | default: defaultVal, 42 | filter: (raw) => { 43 | const url = (raw || '').trim() 44 | const gh = githubUrlToObject(url) 45 | return gh ? `git+ssh://git@github.com/${gh.user}/${gh.repo}.git` : url 46 | }, 47 | validate: (url) => { 48 | if (!url) { 49 | return true 50 | } 51 | 52 | try { 53 | const parsed = new URL(url) 54 | return parsed ? true : 'Invalid URL' 55 | } catch (err) { 56 | return 'Invalid URL' 57 | } 58 | }, 59 | }) 60 | } 61 | -------------------------------------------------------------------------------- /src/cmds/build.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const meow = require('meow') 3 | const pkg = require('../../package.json') 4 | const build = require('../actions/build') 5 | const log = require('../util/log') 6 | const sharedFlags = require('../sharedFlags') 7 | 8 | const allowedSourceMaps = ['true', 'false', 'inline', 'both'] 9 | const description = `Verify, build and compile a Sanity plugin` 10 | 11 | const help = ` 12 | Usage 13 | $ ${pkg.binname} build [] 14 | 15 | Options 16 | --source-maps, -s [${allowedSourceMaps.join('|')}] 17 | --watch Watch for changes and recompile 18 | --silent Do not print info and warning messages 19 | --verbose Log everything. This option conflicts with --silent 20 | --version Output the version number 21 | --help Output usage information 22 | 23 | Examples 24 | # Build the plugin in the current directory 25 | $ ${pkg.binname} build 26 | 27 | # Build the plugin in ~/my-plugin, don't print info/warning messages 28 | $ ${pkg.binname} build ~/my-plugin --silent 29 | 30 | # Build the plugin and recompile automatically on changes 31 | $ ${pkg.binname} build --watch 32 | 33 | # Build the plugin in the current directory, generate inline sourcemaps 34 | $ ${pkg.binname} build --source-maps inline 35 | 36 | # Allow package.json to reference files inside the uncompiled source folder 37 | $ ${pkg.binname} build --allow-source-target 38 | ` 39 | 40 | const flags = { 41 | ...sharedFlags, 42 | watch: { 43 | type: 'boolean', 44 | default: false, 45 | }, 46 | allowSourceTarget: { 47 | type: 'boolean', 48 | default: false, 49 | }, 50 | sourceMaps: { 51 | type: 'string', 52 | default: 'true', 53 | alias: 's', 54 | }, 55 | } 56 | 57 | function run({argv}) { 58 | const cli = meow(help, {flags, argv, description}) 59 | const basePath = path.resolve(cli.input[0] || process.cwd()) 60 | if (!allowedSourceMaps.includes(cli.flags.sourceMaps)) { 61 | log.error(`Invalid --source-maps option: "${cli.flags.sourceMaps}"`) 62 | cli.showHelp() // Exits 63 | } 64 | 65 | return build({basePath, flags: cli.flags}) 66 | } 67 | 68 | module.exports = run 69 | -------------------------------------------------------------------------------- /bin/sanipack.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict' 3 | const meow = require('meow') 4 | const log = require('../src/util/log') 5 | const commands = require('../src/cmds') 6 | const sharedFlags = require('../src/sharedFlags') 7 | const pkg = require('../package.json') 8 | 9 | const cli = meow( 10 | ` 11 | Usage 12 | $ ${pkg.binname} [--help] [--debug] [] 13 | 14 | These are common commands used in various situations: 15 | 16 | build Compile a Sanity plugin (prior to publishing) 17 | init Create a new Sanity plugin 18 | splat Inject ${pkg.name} into an existing Sanity plugin 19 | verify Verify a Sanity plugin prior to publishing 20 | version Show the version of ${pkg.name} currently installed 21 | 22 | Options 23 | --silent Do not print info and warning messages 24 | --verbose Log everything. This option conflicts with --silent 25 | --debug Print stack trace on errors 26 | --version Output the version number 27 | --help Output usage information 28 | 29 | Examples 30 | # Build a Sanity plugin for publishing 31 | $ ${pkg.binname} build 32 | 33 | # Verify that a Sanity plugin is ready to be published 34 | # (great for pre-publish step!) 35 | $ ${pkg.binname} verify 36 | `, 37 | { 38 | autoHelp: false, 39 | flags: sharedFlags, 40 | } 41 | ) 42 | 43 | const commandName = cli.input[0] 44 | 45 | if (!commandName) { 46 | cli.showHelp() // Exits 47 | } 48 | 49 | if (!(commandName in commands)) { 50 | console.error(`Unknown command "${commandName}"`) 51 | cli.showHelp() // Exits 52 | } 53 | 54 | if (cli.flags.silent && cli.flags.verbose) { 55 | log.error(`--silent and --verbose are mutually exclusive`) 56 | cli.showHelp() // Exits 57 | } 58 | 59 | // Lazy-load command 60 | const cmd = require(commands[commandName]) 61 | 62 | // And run it 63 | async function sanipack() { 64 | try { 65 | log.setVerbosity(cli.flags) 66 | await cmd({argv: process.argv.slice(3)}) 67 | } catch (err) { 68 | log.error(err instanceof TypeError || cli.flags.debug ? err.stack : err.message) 69 | 70 | // eslint-disable-next-line no-process-exit 71 | process.exit(1) 72 | } 73 | } 74 | 75 | sanipack() 76 | -------------------------------------------------------------------------------- /test/cli.test.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const execa = require('execa') 3 | const tap = require('tap') 4 | const pkg = require('../package.json') 5 | 6 | const sanipack = path.resolve(__dirname, '..', pkg.bin.sanipack) 7 | const normalize = (dirPath) => dirPath.replace(/\//g, path.sep) 8 | 9 | tap.test('shows help if no command is given', async (t) => { 10 | const {stdout, stderr, exitCode} = await execa(sanipack, {reject: false}) 11 | t.equal(exitCode, 2, 'should have exit code 2') 12 | t.equal(stderr, '') 13 | t.match(stdout, pkg.description) 14 | t.match(stdout, pkg.binname) 15 | }) 16 | 17 | tap.test('shows error + help on unknown commands', async (t) => { 18 | const {stdout, stderr, exitCode} = await execa(sanipack, ['lolwat'], {reject: false}) 19 | t.equal(exitCode, 2, 'should have exit code 2') 20 | t.equal(stderr, 'Unknown command "lolwat"') 21 | t.match(stdout, pkg.description) 22 | t.match(stdout, pkg.binname) 23 | }) 24 | 25 | tap.test('shows error + help when using both --silent and --verbose', async (t) => { 26 | const {stdout, stderr, exitCode} = await execa(sanipack, ['version', '--silent', '--verbose'], { 27 | reject: false, 28 | }) 29 | t.equal(exitCode, 2, 'should have exit code 2') 30 | t.match(stderr, '--silent and --verbose are mutually exclusive') 31 | t.match(stdout, pkg.description) 32 | t.match(stdout, pkg.binname) 33 | }) 34 | 35 | tap.test('shows no stack trace without --debug', async (t) => { 36 | const {stdout, stderr, exitCode} = await execa(sanipack, ['version', '--major', '--minor'], { 37 | reject: false, 38 | }) 39 | t.equal(exitCode, 1, 'should have exit code 1') 40 | t.equal(stdout, '', 'should have empty stdout') 41 | t.match(stderr, 'only one can be used at a time') 42 | t.notMatch(stderr, normalize('/cmds/version.js:')) 43 | }) 44 | 45 | tap.test('shows stack trace with --debug', async (t) => { 46 | const {stdout, stderr, exitCode} = await execa( 47 | sanipack, 48 | ['version', '--debug', '--major', '--minor'], 49 | {reject: false} 50 | ) 51 | t.equal(exitCode, 1, 'should have exit code 1') 52 | t.equal(stdout, '', 'should have empty stdout') 53 | t.match(stderr, 'only one can be used at a time') 54 | t.match(stderr, path.normalize('/cmds/version.js')) 55 | }) 56 | -------------------------------------------------------------------------------- /src/actions/init.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const outdent = require('outdent') 3 | const splat = require('./splat') 4 | const log = require('../util/log') 5 | const {fileExists, writeFile, writeJsonFile, ensureDir} = require('../util/files') 6 | const {resolveLatestVersions} = require('../npm/resolveLatestVersions') 7 | 8 | const defaultDependencies = ['prop-types'] 9 | const defaultDevDependencies = {} 10 | const defaultPeerDependencies = {react: '^17.0.0'} 11 | 12 | const defaultSanityManifest = { 13 | paths: { 14 | source: './src', 15 | compiled: './lib', 16 | }, 17 | parts: [], 18 | } 19 | 20 | const defaultSource = outdent` 21 | import React from 'react' 22 | import PropTypes from 'prop-types' 23 | 24 | const MyPlugin = (props) => { 25 | return
This is a {props.thing}!
26 | } 27 | 28 | MyPlugin.propTypes = { 29 | thing: PropTypes.string, 30 | } 31 | 32 | MyPlugin.defaultProps = { 33 | thing: 'plugin', 34 | } 35 | 36 | export default MyPlugin 37 | `.trimStart() 38 | 39 | module.exports = async function init(options) { 40 | const manifestPath = path.join(options.basePath, 'sanity.json') 41 | 42 | let dependencies = {} 43 | let devDependencies = {} 44 | let peerDependencies = {} 45 | 46 | const hadSanityJson = await fileExists(manifestPath) 47 | if (!hadSanityJson) { 48 | // If we're initializing into a new directory (with no `sanity.json`), 49 | // we'll be writing some sample source code which depends on React. 50 | // We should help out by adding dependencies! 51 | dependencies = {...dependencies, ...(await resolveLatestVersions(defaultDependencies))} 52 | devDependencies = {...devDependencies, ...defaultDevDependencies} 53 | peerDependencies = {...peerDependencies, ...defaultPeerDependencies} 54 | 55 | await writeJsonFile(manifestPath, defaultSanityManifest) 56 | log.info('Wrote sanity.json') 57 | } 58 | 59 | await splat({ 60 | ...options, 61 | requireUserConfirmation: true, 62 | dependencies, 63 | devDependencies, 64 | peerDependencies, 65 | validate: false, 66 | }) 67 | 68 | if (!hadSanityJson) { 69 | const srcDir = path.resolve(options.basePath, defaultSanityManifest.paths.source) 70 | await ensureDir(srcDir) 71 | await writeFile(path.join(srcDir, 'YourPlugin.js'), defaultSource, {encoding: 'utf8'}) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/cmds/splat.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const meow = require('meow') 3 | const pkg = require('../../package.json') 4 | const log = require('../util/log') 5 | const splat = require('../actions/splat') 6 | const {hasSanityJson} = require('../sanity/manifest') 7 | const sharedFlags = require('../sharedFlags') 8 | 9 | const description = `"Splat" configuration into a Sanity plugin` 10 | 11 | const help = ` 12 | Usage 13 | $ ${pkg.binname} splat [] 14 | 15 | Options 16 | --no-eslint Disables ESLint config and dependencies from being added 17 | --no-prettier Disables prettier config and dependencies from being added 18 | --no-license Disables LICENSE + package.json license field from being added 19 | --no-editorconfig Disables .editorconfig from being added 20 | --no-gitignore Disables .gitignore from being added 21 | --no-scripts Disables scripts from being added to package.json 22 | --license [spdx] Use the license with the given SPDX identifier 23 | 24 | Examples 25 | # Splat configuration into the plugin in the current directory 26 | $ ${pkg.binname} splat 27 | 28 | # Splat configuration into the plugin in ~/my-plugin 29 | $ ${pkg.binname} splat ~/my-plugin 30 | 31 | # Don't add eslint or prettier 32 | $ ${pkg.binname} splat --no-eslint --no-prettier 33 | ` 34 | 35 | const flags = { 36 | ...sharedFlags, 37 | eslint: { 38 | type: 'boolean', 39 | default: true, 40 | }, 41 | prettier: { 42 | type: 'boolean', 43 | default: true, 44 | }, 45 | license: { 46 | type: 'string', 47 | }, 48 | editorconfig: { 49 | type: 'boolean', 50 | default: true, 51 | }, 52 | gitignore: { 53 | type: 'boolean', 54 | default: true, 55 | }, 56 | scripts: { 57 | type: 'boolean', 58 | default: true, 59 | }, 60 | } 61 | 62 | async function run({argv}) { 63 | const cli = meow(help, {flags, argv, description}) 64 | const basePath = path.resolve(cli.input[0] || process.cwd()) 65 | 66 | const {exists, isRoot} = await hasSanityJson(basePath) 67 | if (exists && isRoot) { 68 | throw new Error( 69 | `sanity.json has a "root" property set to true - are you trying to splat into a studio instead of a plugin?` 70 | ) 71 | } 72 | 73 | if (!exists) { 74 | throw new Error( 75 | `sanity.json does not exist in this directory, maybe you want "${pkg.binname} init" instead?` 76 | ) 77 | } 78 | 79 | await splat({basePath, flags: cli.flags}) 80 | 81 | log.info('Done!') 82 | } 83 | 84 | module.exports = run 85 | -------------------------------------------------------------------------------- /src/actions/build.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const childProcess = require('child_process') 3 | const npmRunPath = require('npm-run-path') 4 | const findBabelConfig = require('find-babel-config') 5 | const log = require('../util/log') 6 | const {getPaths} = require('../sanity/manifest') 7 | const {getPackage} = require('../npm/package') 8 | const {buildExtensions} = require('../configs/buildExtensions') 9 | 10 | const defaultBabelConfigPath = path.join(__dirname, '..', 'configs', 'babelrc.js') 11 | const noUndefined = (arr) => arr.filter((item) => typeof item !== 'undefined') 12 | 13 | module.exports = async function build({basePath, flags}) { 14 | const pkg = await getPackage({basePath, flags}) 15 | const paths = await getPaths({basePath, pluginName: pkg.name, flags, verifySourceParts: true}) 16 | if (!paths) { 17 | log.warn(`No "paths" property declared in sanity.json, will not compile with babel`) 18 | return 19 | } 20 | 21 | const babelConfig = await findBabelConfig(basePath) 22 | const configPath = babelConfig.file || defaultBabelConfigPath 23 | 24 | log.info('Compiling plugin:') 25 | log.info('Input : %s', paths.source) 26 | log.info('Output: %s', paths.compiled) 27 | 28 | if (flags.watch) { 29 | log.info('👀 Watching for changes') 30 | } 31 | 32 | await spawn( 33 | 'babel', 34 | noUndefined([ 35 | // Booleans 36 | '--copy-files', 37 | '--delete-dir-on-start', 38 | flags.watch ? '--watch' : undefined, 39 | flags.silent ? '--quiet' : undefined, 40 | flags.verbose ? '--verbose' : undefined, 41 | 42 | // Babel configuration 43 | '--config-file', 44 | configPath, 45 | 46 | // Compile JSX, typescript as well 47 | '--extensions', 48 | buildExtensions.join(','), 49 | 50 | // Use source maps? 51 | '--source-maps', 52 | flags.sourceMaps || 'true', 53 | 54 | // Where to actually output the stuff 55 | '--out-dir', 56 | paths.compiled, 57 | 58 | // Where to read source from 59 | paths.source, 60 | ]), 61 | { 62 | env: npmRunPath.env(), 63 | stdio: 'inherit', 64 | } 65 | ) 66 | } 67 | 68 | function spawn(cmd, args, options) { 69 | // ref: https://stackoverflow.com/questions/37459717/error-spawn-enoent-on-windows/37487465 70 | const withShellOptions = process.platform === 'win32' ? {...options, shell: true} : options 71 | 72 | return new Promise((resolve, reject) => { 73 | childProcess.spawn(cmd, args, withShellOptions).on('error', reject).on('close', resolve) 74 | }) 75 | } 76 | -------------------------------------------------------------------------------- /src/util/user.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const xdgBasedir = require('xdg-basedir') 3 | const gitUserInfo = require('git-user-info') 4 | const {validate: isValidEmail} = require('email-validator') 5 | const {readJsonFile} = require('./files') 6 | const {request} = require('./request') 7 | const {prompt} = require('./prompt') 8 | 9 | module.exports = {getUserInfo, getPackageUserInfo} 10 | 11 | async function getUserInfo({requireUserConfirmation} = {}, pkg) { 12 | const userInfo = 13 | getPackageUserInfo(pkg) || (await getSanityUserInfo()) || (await getGitUserInfo()) 14 | return requireUserConfirmation || !userInfo ? promptForInfo(userInfo) : userInfo 15 | } 16 | 17 | function getPackageUserInfo(pkg) { 18 | if (!pkg || !pkg.author) { 19 | return false 20 | } 21 | 22 | if (!pkg.author.includes('@')) { 23 | return {name: pkg.author} 24 | } 25 | 26 | const [pre, ...post] = pkg.author.replace(/[<>[\]]/g, '').split(/@/) 27 | const nameParts = pre.split(/\s+/) 28 | const email = [nameParts[nameParts.length - 1], ...post].join('@') 29 | const name = nameParts.slice(0, -1).join(' ') 30 | return {name, email} 31 | } 32 | 33 | async function promptForInfo(defValue) { 34 | const name = await prompt('Author name', { 35 | filter: filterString, 36 | default: defValue && defValue.name, 37 | validate: requiredString, 38 | }) 39 | 40 | const email = await prompt('Author email', { 41 | filter: filterString, 42 | default: defValue && defValue.email, 43 | validate: validOrEmptyEmail, 44 | }) 45 | 46 | return {name, email} 47 | } 48 | 49 | async function getSanityUserInfo() { 50 | try { 51 | const data = await readJsonFile(path.join(xdgBasedir.config, 'sanity', 'config.json')) 52 | const token = data && data.authToken 53 | 54 | if (!token) { 55 | return null 56 | } 57 | 58 | const user = await request({ 59 | url: 'https://api.sanity.io/v1/users/me', 60 | headers: {Authorization: `Bearer ${token}`}, 61 | }) 62 | 63 | if (!user) { 64 | return null 65 | } 66 | 67 | const {name, email} = user 68 | return {name, email} 69 | } catch (err) { 70 | return null 71 | } 72 | } 73 | 74 | function getGitUserInfo() { 75 | const user = gitUserInfo() 76 | return user ? {name: user.name, email: user.email} : null 77 | } 78 | 79 | function filterString(val) { 80 | return (val || '').trim() 81 | } 82 | 83 | function requiredString(value) { 84 | return value.length > 1 ? true : 'Required' 85 | } 86 | 87 | function validOrEmptyEmail(value) { 88 | if (!value) { 89 | return true 90 | } 91 | 92 | return isValidEmail(value) ? true : 'Must either be a valid email or empty' 93 | } 94 | -------------------------------------------------------------------------------- /src/cmds/init.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const meow = require('meow') 3 | const pkg = require('../../package.json') 4 | const log = require('../util/log') 5 | const init = require('../actions/init') 6 | const {isEmptyish, ensureDir} = require('../util/files') 7 | const {installDependencies, promptForPackageManager} = require('../npm/manager') 8 | const {hasSanityJson} = require('../sanity/manifest') 9 | const {prompt} = require('../util/prompt') 10 | const sharedFlags = require('../sharedFlags') 11 | 12 | const description = `Initialize a new Sanity plugin` 13 | 14 | const help = ` 15 | Usage 16 | $ ${pkg.binname} init [] 17 | 18 | Options 19 | --no-eslint Disables ESLint config and dependencies from being added 20 | --no-prettier Disables prettier config and dependencies from being added 21 | --no-license Disables LICENSE + package.json license field from being added 22 | --no-editorconfig Disables .editorconfig from being added 23 | --no-gitignore Disables .gitignore from being added 24 | --no-scripts Disables scripts from being added to package.json 25 | --license [spdx] Use the license with the given SPDX identifier 26 | 27 | Examples 28 | # Initialize a new plugin in the current directory 29 | $ ${pkg.binname} init 30 | 31 | # Initialize a plugin in the directory ~/my-plugin 32 | $ ${pkg.binname} init ~/my-plugin 33 | 34 | # Don't add eslint or prettier 35 | $ ${pkg.binname} init --no-eslint --no-prettier 36 | ` 37 | 38 | const flags = { 39 | ...sharedFlags, 40 | eslint: { 41 | type: 'boolean', 42 | default: true, 43 | }, 44 | prettier: { 45 | type: 'boolean', 46 | default: true, 47 | }, 48 | license: { 49 | type: 'string', 50 | }, 51 | editorconfig: { 52 | type: 'boolean', 53 | default: true, 54 | }, 55 | gitignore: { 56 | type: 'boolean', 57 | default: true, 58 | }, 59 | scripts: { 60 | type: 'boolean', 61 | default: true, 62 | }, 63 | } 64 | 65 | async function run({argv}) { 66 | const cli = meow(help, {flags, argv, description}) 67 | const basePath = path.resolve(cli.input[0] || process.cwd()) 68 | 69 | const {exists, isRoot} = await hasSanityJson(basePath) 70 | if (exists && isRoot) { 71 | throw new Error( 72 | `sanity.json has a "root" property set to true - are you trying to init into a studio instead of a plugin?` 73 | ) 74 | } 75 | 76 | log.info('Initializing new plugin in "%s"', basePath) 77 | if ( 78 | !(await isEmptyish(basePath)) && 79 | !(await prompt('Directory is not empty, proceed?', {type: 'confirm', default: false})) 80 | ) { 81 | log.error('Directory is not empty. Cancelled.') 82 | return 83 | } 84 | 85 | await ensureDir(basePath) 86 | await init({basePath, flags: cli.flags}) 87 | if (await installDependencies(await promptForPackageManager(), {cwd: basePath})) { 88 | log.info('Done!') 89 | } else { 90 | log.error('Failed to install dependencies, try manually running `npm install`') 91 | } 92 | } 93 | 94 | module.exports = run 95 | -------------------------------------------------------------------------------- /src/util/readme.js: -------------------------------------------------------------------------------- 1 | const outdent = require('outdent') 2 | const licenses = require('@rexxars/choosealicense-list') 3 | const {writeFile} = require('./files') 4 | const {getPackageUserInfo} = require('./user') 5 | 6 | module.exports = {generateReadme, isDefaultGitHubReadme, replaceInReadme} 7 | 8 | function generateReadme(data) { 9 | const {user, pluginName, license, description, distConfig} = data 10 | const shortName = getShortName(pluginName) 11 | 12 | let configurationText = '' 13 | if (distConfig) { 14 | configurationText = outdent` 15 | ## Configuration 16 | 17 | The plugin can be configured through \`${getStubConfigPath(pluginName)}\`: 18 | 19 | \`\`\`json 20 | ${JSON.stringify(distConfig, null, 2)} 21 | \`\`\` 22 | 23 | ` 24 | } 25 | 26 | const descriptionText = description ? `\n${description}\n` : '' 27 | 28 | return outdent` 29 | # ${pluginName} 30 | ${descriptionText} 31 | ## Installation 32 | 33 | \`\`\` 34 | sanity install ${shortName} 35 | \`\`\` 36 | 37 | ${configurationText} 38 | ${getLicenseText(license && license.id, user)} 39 | ` 40 | } 41 | 42 | function getLicenseText(licenseId, user) { 43 | if (!licenseId) { 44 | return '' 45 | } 46 | 47 | let licenseName = licenses.find(licenseId).title 48 | licenseName = licenseName && licenseName.replace(/\s+license$/i, '') 49 | 50 | let licenseText = '## License\n' 51 | if (licenseName && user.name) { 52 | licenseText = `${licenseText}\n${licenseName} © ${user.name}\nSee LICENSE` 53 | } else if (licenseName) { 54 | licenseText = `${licenseText}\n${licenseName}\nSee LICENSE` 55 | } else { 56 | licenseText = `${licenseText}\nSee LICENSE` 57 | } 58 | 59 | return licenseText 60 | } 61 | 62 | function getShortName(pluginName) { 63 | return pluginName.replace(/^sanity-plugin-/, '') 64 | } 65 | 66 | function getStubConfigPath(pluginName) { 67 | return `/config/${getShortName(pluginName)}.json` 68 | } 69 | 70 | async function replaceInReadme(prevReadme, {path, previousPkg, nextPkg, nextUser}) { 71 | if (!prevReadme) { 72 | return false 73 | } 74 | 75 | const previousUser = getPackageUserInfo(previousPkg) 76 | 77 | let newReadme = prevReadme 78 | .replace(previousPkg.name, nextPkg.name) 79 | .replace(getStubConfigPath(previousPkg.name), getStubConfigPath(nextPkg.name)) 80 | .replace( 81 | `sanity install ${getShortName(previousPkg.name)}`, 82 | `sanity install ${getShortName(nextPkg.name)}` 83 | ) 84 | .replace( 85 | getLicenseText(previousPkg.license, previousUser), 86 | getLicenseText(nextPkg.license, nextUser) 87 | ) 88 | 89 | if (previousPkg.description) { 90 | newReadme = newReadme.replace(previousPkg.description, nextPkg.description) 91 | } 92 | 93 | await writeFile(path, newReadme, 'utf8') 94 | return true 95 | } 96 | 97 | function isDefaultGitHubReadme(readme) { 98 | if (!readme) { 99 | return false 100 | } 101 | 102 | const lines = readme.split('\n', 20).filter(Boolean) 103 | 104 | // title + _optional_ description 105 | return lines.length <= 2 && lines[0].startsWith('#') 106 | } 107 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanipack", 3 | "version": "2.1.0", 4 | "description": "Enhanced Sanity.io plugin development experience", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "test": "tap", 8 | "posttest": "eslint ." 9 | }, 10 | "binname": "sanipack", 11 | "bin": { 12 | "sanipack": "./bin/sanipack.js" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+ssh://git@github.com/rexxars/sanipack.git" 17 | }, 18 | "engines": { 19 | "node": ">=12.0.0" 20 | }, 21 | "keywords": [ 22 | "sanity-io", 23 | "sanity", 24 | "plugin", 25 | "development", 26 | "babel", 27 | "typescript", 28 | "bootstrap" 29 | ], 30 | "author": "Espen Hovlandsdal", 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/rexxars/sanipack/issues" 34 | }, 35 | "homepage": "https://github.com/rexxars/sanipack#readme", 36 | "dependencies": { 37 | "@babel/cli": "^7.15.7", 38 | "@babel/core": "^7.15.8", 39 | "@babel/eslint-parser": "^7.15.8", 40 | "@babel/plugin-proposal-class-properties": "^7.14.5", 41 | "@babel/preset-env": "^7.15.8", 42 | "@babel/preset-react": "^7.14.5", 43 | "@babel/preset-typescript": "^7.15.0", 44 | "@babel/traverse": "^7.15.4", 45 | "@rexxars/choosealicense-list": "^1.1.2", 46 | "chalk": "^4.1.2", 47 | "discover-path": "^1.0.0", 48 | "email-validator": "^2.0.4", 49 | "execa": "^5.1.1", 50 | "find-babel-config": "^1.2.0", 51 | "get-it": "^5.0.5", 52 | "get-latest-version": "^2.0.0", 53 | "git-remote-origin-url": "^3.1.0", 54 | "git-user-info": "^1.0.1", 55 | "github-url-to-object": "^4.0.6", 56 | "inquirer": "^8.2.0", 57 | "meow": "^9.0.0", 58 | "npm-packlist": "^3.0.0", 59 | "npm-run-path": "^4.0.1", 60 | "outdent": "^0.8.0", 61 | "p-any": "^3.0.0", 62 | "p-props": "^4.0.0", 63 | "postcss": "^8.3.9", 64 | "semver": "^7.3.5", 65 | "spdx-license-ids": "^3.0.10", 66 | "validate-npm-package-name": "^3.0.0", 67 | "xdg-basedir": "^4.0.0" 68 | }, 69 | "devDependencies": { 70 | "eslint": "^8.0.0", 71 | "eslint-config-prettier": "^8.3.0", 72 | "eslint-config-sanity": "^5.1.0", 73 | "prettier": "^2.4.1", 74 | "readdirp": "^3.6.0", 75 | "rimraf": "^3.0.2", 76 | "tap": "^15.0.10" 77 | }, 78 | "tap": { 79 | "jobs": 2, 80 | "browser": false, 81 | "timeout": 120, 82 | "reporter": "spec", 83 | "check-coverage": false, 84 | "coverage-report": [ 85 | "html" 86 | ] 87 | }, 88 | "prettier": { 89 | "semi": false, 90 | "printWidth": 100, 91 | "bracketSpacing": false, 92 | "singleQuote": true 93 | }, 94 | "eslintConfig": { 95 | "extends": [ 96 | "sanity", 97 | "prettier" 98 | ], 99 | "env": { 100 | "node": true, 101 | "browser": true 102 | }, 103 | "parserOptions": { 104 | "ecmaVersion": 2018 105 | }, 106 | "rules": { 107 | "no-await-in-loop": "off", 108 | "no-console": "off", 109 | "complexity": "off", 110 | "id-length": "off", 111 | "max-depth": "off", 112 | "no-sync": "off", 113 | "strict": "off" 114 | }, 115 | "ignorePatterns": [ 116 | "test/fixtures/**" 117 | ] 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sanipack 2 | 3 | [![npm version](https://img.shields.io/npm/v/sanipack.svg?style=flat-square)](https://www.npmjs.com/package/sanipack)[![Build Status](https://img.shields.io/github/workflow/status/rexxars/sanipack/CI/main.svg?style=flat-square)](https://github.com/rexxars/sanipack/actions?query=workflow%3ACI) 4 | 5 | An opinionated, enhanced [Sanity.io](https://www.sanity.io/) plugin development experience. 6 | 7 | ## Features 8 | 9 | - Bootstrap new plugins with (opinionated) tooling: 10 | - [ESLint](https://eslint.org/) (with [Sanity config](https://github.com/sanity-io/sanity/tree/next/packages/eslint-config-sanity)) 11 | - [Prettier](https://prettier.io/) (with Sanity settings) 12 | - [EditorConfig](https://editorconfig.org/) (with Sanity settings) 13 | - [.gitignore](https://git-scm.com/docs/gitignore) + [.npmignore](https://docs.npmjs.com/cli/v6/using-npm/developers#keeping-files-out-of-your-package) 14 | - Build scripts (pre-publish build + verify) 15 | - Verifies plugin conventions before publishing: 16 | - No unused dependencies 17 | - No undeclared dependencies 18 | - Referenced files exist, has correct casing and is publishable 19 | - Has an [SPDX](https://spdx.org/licenses/) compatible license definition 20 | - Has a valid plugin config, if present 21 | - `react`/`react-dom` declared as peer dependencies, if used 22 | - ... and more ... 23 | - Compiles plugin source code using Babel 24 | 25 | ## Quick start 26 | 27 | ```bash 28 | # Initialize a new plugin (outside of your Sanity studio folder) 29 | npx sanipack init sanity-plugin-spotify 30 | 31 | # Make your plugin linkable, and compile an initial version 32 | cd sanity-plugin-spotify 33 | npm link 34 | npm run build 35 | 36 | # Link the plugin to your Sanity studio and start it 37 | cd /path/to/my-studio 38 | npm link sanity-plugin-spotify 39 | sanity start 40 | 41 | # In another terminal, start a watch task for your plugin 42 | cd /path/to/sanity-plugin-spotify 43 | npm run watch 44 | ``` 45 | 46 | ## Usage 47 | 48 | ``` 49 | Enhanced Sanity.io plugin development experience 50 | 51 | Usage 52 | $ sanipack [--help] [--debug] [] 53 | 54 | These are common commands used in various situations: 55 | 56 | build Compile a Sanity plugin (prior to publishing) 57 | init Create a new Sanity plugin 58 | splat Inject sanipack into an existing Sanity plugin 59 | verify Verify a Sanity plugin prior to publishing 60 | version Show the version of sanipack currently installed 61 | 62 | Options 63 | --silent Do not print info and warning messages 64 | --verbose Log everything. This option conflicts with --silent 65 | --debug Print stack trace on errors 66 | --version Output the version number 67 | --help Output usage information 68 | 69 | Examples 70 | # Build a Sanity plugin for publishing 71 | $ sanipack build 72 | 73 | # Verify that a Sanity plugin is ready to be published 74 | # (great for pre-publish step!) 75 | $ sanipack verify 76 | ``` 77 | 78 | Use the `--help` flag on each command for more information on their usage, eg `sanipack build --help`. 79 | 80 | ## Publishing a plugin 81 | 82 | **Note:** If you're writing a plugin that is only useful for yourself or your company, you might want to either put the plugin inside of the `plugins` folder of your Sanity studio (saves you from having to publish at all), or if shared across multiple "private" studios: register an organization on npm and make sure your module is [prefixed with the organization scope](https://docs.npmjs.com/creating-and-publishing-private-packages), eg `@your-company/plugin-name`. 83 | 84 | Also; you cannot easily remove modules/versions from npm once published. Take a good look at your `package.json` to see that the fields in there makes sense to you, and make sure there are no "secrets" (authorization tokens, API keys or similar) in the plugin directory - anything not listed in `.npmignore` will be part of the published module. 85 | 86 | When you're ready to publish, run `npm publish` (or `yarn publish` if you prefer). The `prepublishOnly` task should kick in and compile the source files, then verify the built output to ensure it looks good. 87 | 88 | If you have not published any modules to npm before, you will be asked to create a user first. 89 | 90 | ## FAQ 91 | 92 | **Q:** Do I _have_ to use this for developing Sanity plugins? 93 | 94 | **A:** Absolutely not! Make sure your Sanity plugin is ES5-compatible and that your `sanity.json` file and any references parts refer to the right directories, and you're good to go. This package was created to make it easier to set up the build toolchain and prevent common mistakes. If you know what you're doing and don't like any magic, roll your own thing! :) 95 | 96 | ## License 97 | 98 | MIT © [Espen Hovlandsdal](https://espen.codes/) 99 | -------------------------------------------------------------------------------- /test/build.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const util = require('util') 4 | const execa = require('execa') 5 | const readdirp = require('readdirp') 6 | const tap = require('tap') 7 | const pkg = require('../package.json') 8 | 9 | const rimraf = util.promisify(require('rimraf')) 10 | const readFileRaw = util.promisify(fs.readFile) 11 | const readFile = (file) => readFileRaw(file, 'utf8') 12 | const baseFixturesDir = path.join(__dirname, 'fixtures', 'build') 13 | const sanipack = path.resolve(__dirname, '..', pkg.bin.sanipack) 14 | const onlyPaths = (files) => files.map((file) => file.path) 15 | const contents = (dir) => readdirp.promise(dir).then(onlyPaths) 16 | const normalize = (dirPath) => dirPath.replace(/\//g, path.sep) 17 | 18 | const options = {timeout: 15000} 19 | const expectedFiles = ['one.js', 'one.js.map', 'two.js', 'two.js.map', 'styles/one.css'].map( 20 | normalize 21 | ) 22 | 23 | tap.test('can build valid plugin (in cwd)', options, async (t) => { 24 | const fixtureDir = path.join(baseFixturesDir, 'valid') 25 | const outputDir = path.join(fixtureDir, 'lib') 26 | 27 | await rimraf(outputDir) 28 | 29 | const {stdout, stderr} = await execa(sanipack, ['build'], {cwd: fixtureDir}) 30 | t.equal(stderr, '', 'should have empty stderr') 31 | t.match(stdout, 'compiled 2 files') 32 | t.strictSame(await contents(outputDir), expectedFiles) 33 | t.match(await readFile(path.join(outputDir, 'one.js')), 'interopRequireDefault') 34 | t.match(await readFile(path.join(outputDir, 'styles', 'one.css')), 'bf1942') 35 | 36 | await rimraf(outputDir) 37 | }) 38 | 39 | tap.test('can build valid plugin (specified path)', options, async (t) => { 40 | const fixtureDir = path.join(baseFixturesDir, 'valid') 41 | const outputDir = path.join(fixtureDir, 'lib') 42 | 43 | await rimraf(outputDir) 44 | 45 | const {stdout, stderr} = await execa(sanipack, ['build', fixtureDir]) 46 | t.equal(stderr, '', 'should have empty stderr') 47 | t.match(stdout, '/valid/src') 48 | t.match(stdout, '/valid/lib') 49 | t.match(stdout, 'compiled 2 files') 50 | t.strictSame(await contents(outputDir), expectedFiles) 51 | t.match(await readFile(path.join(outputDir, 'one.js')), 'interopRequireDefault') 52 | t.match(await readFile(path.join(outputDir, 'styles', 'one.css')), 'bf1942') 53 | 54 | await rimraf(outputDir) 55 | }) 56 | 57 | tap.test('can build valid plugin (silently)', options, async (t) => { 58 | const fixtureDir = path.join(baseFixturesDir, 'valid') 59 | const outputDir = path.join(fixtureDir, 'lib') 60 | 61 | await rimraf(outputDir) 62 | 63 | const {stdout, stderr} = await execa(sanipack, ['build', fixtureDir, '--silent']) 64 | t.equal(stderr, '', 'should have empty stderr') 65 | t.equal(stdout, '', 'should have empty stdout') 66 | t.strictSame(await contents(outputDir), expectedFiles) 67 | t.match(await readFile(path.join(outputDir, 'one.js')), 'interopRequireDefault') 68 | t.match(await readFile(path.join(outputDir, 'styles', 'one.css')), 'bf1942') 69 | 70 | await rimraf(outputDir) 71 | }) 72 | 73 | tap.test('can build typescript plugin', options, async (t) => { 74 | const fixtureDir = path.join(baseFixturesDir, 'ts') 75 | const outputDir = path.join(fixtureDir, 'lib') 76 | 77 | await rimraf(outputDir) 78 | 79 | const {stdout, stderr} = await execa(sanipack, ['build'], {cwd: fixtureDir}) 80 | t.equal(stderr, '', 'should have empty stderr') 81 | t.match(stdout, '/ts/src') 82 | t.match(stdout, '/ts/lib') 83 | t.match(stdout, 'compiled 2 files') 84 | t.strictSame(await contents(outputDir), expectedFiles) 85 | t.match(await readFile(path.join(outputDir, 'one.js')), 'interopRequireDefault') 86 | t.match(await readFile(path.join(outputDir, 'styles', 'one.css')), 'bf1942') 87 | 88 | await rimraf(outputDir) 89 | }) 90 | 91 | tap.test('can "build" (skip) plugin without compilation', options, async (t) => { 92 | const fixtureDir = path.join(baseFixturesDir, 'plain') 93 | const {stdout, stderr} = await execa(sanipack, ['build'], {cwd: fixtureDir}) 94 | const before = await contents(fixtureDir) 95 | t.match(stderr, 'will not compile') 96 | t.equal(stdout, '', 'should have empty stdout') 97 | t.strictSame(await contents(fixtureDir), before) 98 | }) 99 | 100 | tap.test('can "build" (skip) plugin without compilation (silent)', options, async (t) => { 101 | const fixtureDir = path.join(baseFixturesDir, 'plain') 102 | const {stdout, stderr} = await execa(sanipack, ['build', '--silent'], {cwd: fixtureDir}) 103 | const before = await contents(fixtureDir) 104 | t.equal(stderr, '', 'should have empty stderr') 105 | t.equal(stdout, '', 'should have empty stdout') 106 | t.strictSame(await contents(fixtureDir), before) 107 | }) 108 | 109 | tap.test('throws on invalid source map flag', options, async (t) => { 110 | const fixtureDir = path.join(baseFixturesDir, 'valid') 111 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', '--source-maps', 'foo'], { 112 | cwd: fixtureDir, 113 | reject: false, 114 | }) 115 | const before = await contents(fixtureDir) 116 | t.equal(exitCode, 2) 117 | t.match(stderr, 'Invalid --source-maps option: "foo"') 118 | t.match(stdout, '[true|false|inline|both]') 119 | t.strictSame(await contents(fixtureDir), before) 120 | }) 121 | -------------------------------------------------------------------------------- /src/dependencies/find.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const postcss = require('postcss') 4 | const {discoverPathSync} = require('discover-path') 5 | const {default: traverse} = require('@babel/traverse') 6 | const {parseSync} = require('@babel/core') 7 | 8 | module.exports = {findDependencies} 9 | 10 | const partReg = /^(all:part|part|config|sanity):/ 11 | const importReg = /^(?:"([^"]+)"|'([^']+)')$/ 12 | const composesReg = /^(.+?)\s+from\s+(?:"([^"]+)"|'([^']+)'|(global))$/ 13 | 14 | function findDependenciesFromFiles(files, seen = new Set()) { 15 | const dependencies = new Set() 16 | files.forEach((file) => findDependencies(file, seen).forEach((dep) => dependencies.add(dep))) 17 | return Array.from(dependencies) 18 | } 19 | 20 | function findDependenciesInCss(css, entryPath, processDependency) { 21 | let ast 22 | try { 23 | ast = postcss.parse(css) 24 | } catch (err) { 25 | throw new Error(`Error parsing file (${entryPath}): ${err.message}`) 26 | } 27 | 28 | ast.walkDecls(/^composes/, (decl) => { 29 | const matches = decl.value.match(composesReg) 30 | if (!matches) { 31 | return 32 | } 33 | 34 | const [, , doubleQuotePath, singleQuotePath] = matches 35 | const importPath = doubleQuotePath || singleQuotePath 36 | if (importPath) { 37 | processDependency(importPath) 38 | } 39 | }) 40 | 41 | ast.walkAtRules('import', (rule) => { 42 | const matches = rule.params.match(importReg) 43 | if (!matches) { 44 | return 45 | } 46 | 47 | const [, doubleQuotePath, singleQuotePath] = matches 48 | const importPath = doubleQuotePath || singleQuotePath 49 | if (importPath) { 50 | processDependency(importPath) 51 | } 52 | }) 53 | } 54 | 55 | function findDependenciesInJs(js, entryPath, processDependency) { 56 | let ast 57 | try { 58 | ast = parseSync(js, {babelrc: false}) 59 | } catch (err) { 60 | throw new Error(`Error parsing file (${entryPath}): ${err.message}`) 61 | } 62 | 63 | traverse(ast, { 64 | ImportDeclaration({node}) { 65 | processDependency(node.source.value) 66 | }, 67 | 68 | CallExpression({node}) { 69 | if (node.callee.name === 'require') { 70 | processDependency(node.arguments[0].value) 71 | } 72 | }, 73 | }) 74 | } 75 | 76 | function findDependencies(entryPath, seen = new Set()) { 77 | if (Array.isArray(entryPath)) { 78 | return findDependenciesFromFiles(entryPath, seen) 79 | } 80 | 81 | seen.add(entryPath) 82 | 83 | let content 84 | try { 85 | content = fs.readFileSync(entryPath, 'utf8') 86 | } catch (err) { 87 | throw new Error(`Error reading file (${entryPath}): ${err.message}`) 88 | } 89 | 90 | const dir = path.dirname(entryPath) 91 | const dependencies = new Set() 92 | 93 | if (entryPath.endsWith('.css')) { 94 | findDependenciesInCss(content, entryPath, processDependency) 95 | } else { 96 | findDependenciesInJs(content, entryPath, processDependency) 97 | } 98 | 99 | function processDependency(requirePath) { 100 | if (typeof requirePath !== 'string') { 101 | return 102 | } 103 | 104 | // Don't allow absolute requires 105 | if (path.isAbsolute(requirePath)) { 106 | throw new Error( 107 | `Absolute paths cannot be used in require/import statements: ${entryPath} references path "${requirePath}"` 108 | ) 109 | } 110 | 111 | const isRelative = requirePath.startsWith('.') 112 | const depPath = isRelative && resolveDependency(dir, requirePath, entryPath) 113 | 114 | if ( 115 | depPath && 116 | ['.js', '.css', '.esm', '.mjs', '.jsx'].includes(path.extname(depPath)) && 117 | !seen.has(depPath) 118 | ) { 119 | // For relative javascript/css requires, recurse to find all depdendencies 120 | findDependencies(depPath, seen).forEach((dep) => dependencies.add(dep)) 121 | return 122 | } 123 | 124 | if (isRelative) { 125 | // Not JS? Skip it 126 | return 127 | } 128 | 129 | // For parts, we want the entire path, as we might want to validate them 130 | if (partReg.test(requirePath)) { 131 | dependencies.add(requirePath) 132 | return 133 | } 134 | 135 | // For modules, resolve the base module name, then add them 136 | // eg: `codemirror/mode/javascript` => `codemirror` 137 | // eg: `@sanity/base/foo/bar.js` => `@sanity/base` 138 | const dep = requirePath.startsWith('@') 139 | ? requirePath.replace(/^(@[^/]+\/[^/]+)(\/.*|$)/, '$1') 140 | : requirePath.replace(/^([^/]+)(\/.*|$)/, '$1') 141 | 142 | dependencies.add(dep) 143 | } 144 | 145 | return Array.from(dependencies) 146 | } 147 | 148 | function resolveDependency(fromDir, toPath, entryPath) { 149 | const [querylessPath] = toPath.split('?', 1) 150 | 151 | let depPath 152 | try { 153 | depPath = require.resolve(path.resolve(fromDir, querylessPath)) 154 | } catch (err) { 155 | throw new Error(`Unable to resolve "${querylessPath}" from ${entryPath}`) 156 | } 157 | 158 | let actualPath 159 | try { 160 | actualPath = discoverPathSync(depPath) 161 | } catch (err) { 162 | const paths = (err.suggestions || []).map((suggested) => 163 | getDidYouMeanPath(querylessPath, suggested) 164 | ) 165 | const didYouMean = paths ? `Did you mean:\n${paths.join('\n- ')}` : '' 166 | throw new Error(`Unable to resolve "${querylessPath}" from ${entryPath}. ${didYouMean}`) 167 | } 168 | 169 | if (actualPath !== depPath) { 170 | const didYouMean = getDidYouMeanPath(querylessPath, actualPath) 171 | throw new Error( 172 | `Unable to resolve "${querylessPath} from ${entryPath}. Did you mean "${didYouMean}"?` 173 | ) 174 | } 175 | 176 | return actualPath 177 | } 178 | 179 | function getDidYouMeanPath(wanted, suggested) { 180 | const end = wanted.replace(/[./]+/, '') 181 | const start = wanted.slice(0, 0 - end.length) 182 | return `${start}${suggested.slice(0 - end.length)}` 183 | } 184 | -------------------------------------------------------------------------------- /test/build-npm.test.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const execa = require('execa') 3 | const tap = require('tap') 4 | const pkg = require('../package.json') 5 | 6 | const baseFixturesDir = path.join(__dirname, 'fixtures', 'build-npm') 7 | const sanipack = path.resolve(__dirname, '..', pkg.bin.sanipack) 8 | const options = {timeout: 15000} 9 | 10 | tap.test('throws on missing package.json', options, async (t) => { 11 | const fixtureDir = path.join(baseFixturesDir, 'no-package-json') 12 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 13 | t.equal(stdout, '', 'should have empty stdout') 14 | t.equal(exitCode, 1, 'should have exit code 1') 15 | t.match(stderr, 'No package.json found') 16 | }) 17 | 18 | tap.test('throws on package.json being... not a file', options, async (t) => { 19 | const fixtureDir = path.join(baseFixturesDir, 'folder-package-json') 20 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 21 | t.equal(stdout, '', 'should have empty stdout') 22 | t.equal(exitCode, 1, 'should have exit code 1') 23 | t.match(stderr, 'EISDIR') 24 | }) 25 | 26 | tap.test('throws on package.json being invalid JSON', options, async (t) => { 27 | const fixtureDir = path.join(baseFixturesDir, 'invalid-package-json') 28 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 29 | t.equal(stdout, '', 'should have empty stdout') 30 | t.equal(exitCode, 1, 'should have exit code 1') 31 | t.match(stderr, 'Unexpected token') 32 | }) 33 | 34 | tap.test('throws on package.json being invalid JSON (not an object)', options, async (t) => { 35 | const fixtureDir = path.join(baseFixturesDir, 'invalid-package-json-shape') 36 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 37 | t.equal(stdout, '', 'should have empty stdout') 38 | t.equal(exitCode, 1, 'should have exit code 1') 39 | t.match(stderr, 'Root must be an object') 40 | }) 41 | 42 | tap.test('throws on package.json being invalid (non-string name)', options, async (t) => { 43 | const fixtureDir = path.join(baseFixturesDir, 'misnamed-package-json') 44 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 45 | t.equal(stdout, '', 'should have empty stdout') 46 | t.equal(exitCode, 1, 'should have exit code 1') 47 | t.match(stderr, '"name" must be a string') 48 | }) 49 | 50 | tap.test('throws on package.json being invalid (not allowed npm name)', options, async (t) => { 51 | const fixtureDir = path.join(baseFixturesDir, 'disallowed-package-json') 52 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 53 | t.equal(stdout, '', 'should have empty stdout') 54 | t.equal(exitCode, 1, 'should have exit code 1') 55 | t.match(stderr, 'name can only contain URL-friendly characters') 56 | }) 57 | 58 | tap.test('throws on package.json being invalid (unscoped without plugin prefix)', options, async (t) => { 59 | const fixtureDir = path.join(baseFixturesDir, 'unprefixed-package-json') 60 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 61 | t.equal(stdout, '', 'should have empty stdout') 62 | t.equal(exitCode, 1, 'should have exit code 1') 63 | t.match(stderr, 'prefixed with "sanity-plugin-"') 64 | }) 65 | 66 | tap.test('throws on package.json being invalid (non-string "main")', options, async (t) => { 67 | const fixtureDir = path.join(baseFixturesDir, 'nonstring-main-package-json') 68 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 69 | t.equal(stdout, '', 'should have empty stdout') 70 | t.equal(exitCode, 1, 'should have exit code 1') 71 | t.match(stderr, '"main" must be a string if defined') 72 | }) 73 | 74 | tap.test('throws on package.json being invalid (references source dir)', options, async (t) => { 75 | const fixtureDir = path.join(baseFixturesDir, 'sourced-package-json') 76 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 77 | t.equal(stdout, '', 'should have empty stdout') 78 | t.equal(exitCode, 1, 'should have exit code 1') 79 | t.match(stderr, '"main" points to file within source') 80 | }) 81 | 82 | tap.test('throws on package.json being invalid (references orphaned file)', options, async (t) => { 83 | const fixtureDir = path.join(baseFixturesDir, 'orphaned-package-json') 84 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 85 | t.equal(stdout, '', 'should have empty stdout') 86 | t.equal(exitCode, 1, 'should have exit code 1') 87 | t.match(stderr, '"main" points to file that will not exist after compiling') 88 | }) 89 | 90 | tap.test('throws on package.json being invalid (references missing file)', options, async (t) => { 91 | const fixtureDir = path.join(baseFixturesDir, 'targetless-package-json') 92 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 93 | t.equal(stdout, '', 'should have empty stdout') 94 | t.equal(exitCode, 1, 'should have exit code 1') 95 | t.match( 96 | stderr, 97 | '"main" points to file that does not exist, and no equivalent is found in source directory' 98 | ) 99 | }) 100 | 101 | tap.test( 102 | 'throws on package.json being invalid (references missing file outside source directory)', 103 | async (t) => { 104 | const fixtureDir = path.join(baseFixturesDir, 'outscoped-package-json') 105 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 106 | t.equal(stdout, '', 'should have empty stdout') 107 | t.equal(exitCode, 1, 'should have exit code 1') 108 | t.match( 109 | stderr, 110 | '"main" points to file that does not exist, and "paths" is not configured to compile to this location' 111 | ) 112 | } 113 | ) 114 | 115 | tap.test('throws on package.json being invalid (references file without `paths`)', options, async (t) => { 116 | const fixtureDir = path.join(baseFixturesDir, 'pathless-package-json') 117 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 118 | t.equal(stdout, '', 'should have empty stdout') 119 | t.equal(exitCode, 1, 'should have exit code 1') 120 | t.match(stderr, '"main" points to file that does not exist') 121 | }) 122 | 123 | tap.test('throws on double lockfile', options, async (t) => { 124 | const fixtureDir = path.join(baseFixturesDir, 'double-lockfile') 125 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 126 | t.equal(stdout, '', 'should have empty stdout') 127 | t.equal(exitCode, 1, 'should have exit code 1') 128 | t.match(stderr, 'contains both package-lock.json and yarn.lock') 129 | }) 130 | -------------------------------------------------------------------------------- /src/util/files.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const util = require('util') 4 | const pAny = require('p-any') 5 | const crypto = require('crypto') 6 | const {buildExtensions} = require('../configs/buildExtensions') 7 | const {uselessFiles} = require('../configs/uselessFiles') 8 | const {prompt} = require('./prompt') 9 | 10 | const stat = util.promisify(fs.stat) 11 | const mkdir = util.promisify(fs.mkdir) 12 | const readdir = util.promisify(fs.readdir) 13 | const copyFile = util.promisify(fs.copyFile) 14 | const readFile = util.promisify(fs.readFile) 15 | const writeFile = util.promisify(fs.writeFile) 16 | 17 | module.exports = { 18 | copyFile, 19 | ensureDir, 20 | hasSourceEquivalent, 21 | hasSourceFile, 22 | hasCompiledFile, 23 | fileExists, 24 | readFile, 25 | readJsonFile, 26 | writeFile, 27 | writeJsonFile, 28 | uselessFiles, 29 | copyFileWithOverwritePrompt, 30 | writeFileWithOverwritePrompt, 31 | isEmptyish, 32 | } 33 | 34 | function hasSourceEquivalent(compiledFile, paths) { 35 | if (!paths.source) { 36 | return fileExists( 37 | path.isAbsolute(compiledFile) ? compiledFile : path.resolve(paths.basePath, compiledFile) 38 | ) 39 | } 40 | 41 | // /plugin/lib/MyComponent.js => /plugin/src 42 | const baseDir = path.dirname(compiledFile.replace(paths.compiled, paths.source)) 43 | 44 | // /plugin/lib/MyComponent.js => MyComponent 45 | const baseName = path.basename(compiledFile, path.extname(compiledFile)) 46 | 47 | // MyComponent => /plugin/src/MyComponent 48 | const pathStub = path.join(baseDir, baseName) 49 | 50 | /* 51 | * /plugin/src/MyComponent => [ 52 | * /plugin/src/MyComponent.jsx, 53 | * /plugin/src/MyComponent.mjs, 54 | * ... 55 | * ] 56 | */ 57 | return buildCandidateExists(pathStub) 58 | } 59 | 60 | // Generally used for parts resolving 61 | async function hasSourceFile(filePath, paths) { 62 | if (!paths.source) { 63 | return fileExists(path.isAbsolute(filePath) ? filePath : path.resolve(paths.basePath, filePath)) 64 | } 65 | 66 | // filePath: components/SomeInput 67 | // paths: {source: '/plugin/src'} 68 | // MyComponent => /plugin/src/MyComponent 69 | const pathStub = path.isAbsolute(filePath) ? filePath : path.resolve(paths.source, filePath) 70 | 71 | if (await fileExists(pathStub)) { 72 | return true 73 | } 74 | 75 | return buildCandidateExists(pathStub) 76 | } 77 | 78 | // Generally used for parts resolving 79 | function hasCompiledFile(filePath, paths) { 80 | if (!paths.compiled) { 81 | return fileExists(path.isAbsolute(filePath) ? filePath : path.resolve(paths.basePath, filePath)) 82 | } 83 | 84 | // filePath: components/SomeInput 85 | // paths: {compiled: '/plugin/lib'} 86 | 87 | // components/SomeInput => /plugin/lib/components/SomeInput 88 | const absPath = path.isAbsolute(filePath) ? filePath : path.resolve(paths.compiled, filePath) 89 | 90 | // /plugin/lib/components/SomeInput => /plugin/lib/components/SomeInput.js 91 | // /plugin/lib/components/SomeInput.js => /plugin/lib/components/SomeInput.js 92 | // /plugin/lib/components/SomeInput.css => /plugin/lib/components/SomeInput.css 93 | const fileExt = path.extname(absPath) 94 | const withExt = fileExt === '' ? `${absPath}.js` : absPath 95 | 96 | return fileExists(withExt) 97 | } 98 | 99 | function buildCandidateExists(pathStub) { 100 | const candidates = buildExtensions.map((extCandidate) => `${pathStub}${extCandidate}`) 101 | 102 | return pAny(candidates.map((candidate) => stat(candidate))) 103 | .then(() => true) 104 | .catch(() => false) 105 | } 106 | 107 | function fileExists(filePath) { 108 | return stat(filePath) 109 | .then(() => true) 110 | .catch(() => false) 111 | } 112 | 113 | async function readJsonFile(filePath) { 114 | const content = await readFile(filePath, 'utf8') 115 | return JSON.parse(content) 116 | } 117 | 118 | function writeJsonFile(filePath, content) { 119 | const data = JSON.stringify(content, null, 2) 120 | return writeFile(filePath, data, {encoding: 'utf8'}) 121 | } 122 | 123 | async function writeFileWithOverwritePrompt(filePath, content, options) { 124 | const {default: defaultVal, ...writeOptions} = options 125 | const withinCwd = filePath.startsWith(process.cwd()) 126 | const printablePath = withinCwd ? path.relative(process.cwd(), filePath) : filePath 127 | 128 | if (await fileEqualsData(filePath, content)) { 129 | return false 130 | } 131 | 132 | if ( 133 | (await fileExists(filePath)) && 134 | !(await prompt(`File "${printablePath}" already exists. Overwrite?`, { 135 | type: 'confirm', 136 | default: defaultVal, 137 | })) 138 | ) { 139 | return false 140 | } 141 | 142 | await writeFile(filePath, content, writeOptions) 143 | return true 144 | } 145 | 146 | async function copyFileWithOverwritePrompt(from, to) { 147 | const withinCwd = to.startsWith(process.cwd()) 148 | const printablePath = withinCwd ? path.relative(process.cwd(), to) : to 149 | 150 | if (await filesAreEqual(from, to)) { 151 | return false 152 | } 153 | 154 | if ( 155 | (await fileExists(to)) && 156 | !(await prompt(`File "${printablePath}" already exists. Overwrite?`, { 157 | type: 'confirm', 158 | default: false, 159 | })) 160 | ) { 161 | return false 162 | } 163 | 164 | await copyFile(from, to) 165 | return true 166 | } 167 | 168 | async function fileEqualsData(filePath, content) { 169 | const contentHash = crypto.createHash('sha1').update(content).digest('hex') 170 | const remoteHash = await getFileHash(filePath) 171 | return contentHash === remoteHash 172 | } 173 | 174 | async function filesAreEqual(file1, file2) { 175 | const [hash1, hash2] = await Promise.all([getFileHash(file1, false), getFileHash(file2)]) 176 | return hash1 === hash2 177 | } 178 | 179 | function getFileHash(filePath, allowMissing = true) { 180 | return new Promise((resolve, reject) => { 181 | const hash = crypto.createHash('sha1') 182 | const stream = fs.createReadStream(filePath) 183 | stream.on('error', (err) => { 184 | if (err.code === 'ENOENT' && allowMissing) { 185 | resolve(null) 186 | } else { 187 | reject(err) 188 | } 189 | }) 190 | 191 | stream.on('end', () => resolve(hash.digest('hex'))) 192 | stream.on('data', (chunk) => hash.update(chunk)) 193 | }) 194 | } 195 | 196 | async function ensureDir(dirPath) { 197 | try { 198 | await mkdir(dirPath) 199 | } catch (err) { 200 | if (err.code !== 'EEXIST') { 201 | throw err 202 | } 203 | } 204 | } 205 | 206 | async function isEmptyish(dirPath) { 207 | const ignoredFiles = ['.git', '.gitignore', 'license', 'readme.md'] 208 | const allFiles = await readdir(dirPath).catch(() => []) 209 | const files = allFiles.filter((file) => !ignoredFiles.includes(file.toLowerCase())) 210 | return files.length === 0 211 | } 212 | -------------------------------------------------------------------------------- /test/build-sanity.test.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const execa = require('execa') 3 | const tap = require('tap') 4 | const pkg = require('../package.json') 5 | 6 | const baseFixturesDir = path.join(__dirname, 'fixtures', 'build-sanity') 7 | const sanipack = path.resolve(__dirname, '..', pkg.bin.sanipack) 8 | const options = {timeout: 15000} 9 | 10 | tap.test('throws on missing sanity.json', options, async (t) => { 11 | const fixtureDir = path.join(baseFixturesDir, 'no-sanity-json') 12 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 13 | t.equal(stdout, '', 'should have empty stdout') 14 | t.equal(exitCode, 1, 'should have exit code 1') 15 | t.match(stderr, 'No sanity.json found') 16 | }) 17 | 18 | tap.test('throws on sanity.json being... not a file', options, async (t) => { 19 | const fixtureDir = path.join(baseFixturesDir, 'folder-sanity-json') 20 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 21 | t.equal(stdout, '', 'should have empty stdout') 22 | t.equal(exitCode, 1, 'should have exit code 1') 23 | t.match(stderr, 'EISDIR') 24 | }) 25 | 26 | tap.test('throws on sanity.json being invalid JSON', options, async (t) => { 27 | const fixtureDir = path.join(baseFixturesDir, 'invalid-sanity-json') 28 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 29 | t.equal(stdout, '', 'should have empty stdout') 30 | t.equal(exitCode, 1, 'should have exit code 1') 31 | t.match(stderr, 'Unexpected token') 32 | }) 33 | 34 | tap.test('throws on sanity.json being invalid JSON (not an object)', options, async (t) => { 35 | const fixtureDir = path.join(baseFixturesDir, 'invalid-sanity-json-shape') 36 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 37 | t.equal(stdout, '', 'should have empty stdout') 38 | t.equal(exitCode, 1, 'should have exit code 1') 39 | t.match(stderr, 'Root must be an object') 40 | }) 41 | 42 | tap.test('throws on sanity.json being invalid (non-boolean root)', options, async (t) => { 43 | const fixtureDir = path.join(baseFixturesDir, 'nonbool-sanity-json') 44 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 45 | t.equal(stdout, '', 'should have empty stdout') 46 | t.equal(exitCode, 1, 'should have exit code 1') 47 | t.match(stderr, '"root" property must be a boolean') 48 | }) 49 | 50 | tap.test('throws on sanity.json being invalid (contains project props)', options, async (t) => { 51 | const fixtureDir = path.join(baseFixturesDir, 'disallowed-sanity-json') 52 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 53 | t.equal(stdout, '', 'should have empty stdout') 54 | t.equal(exitCode, 1, 'should have exit code 1') 55 | t.match(stderr, 'Keys "api", "project" are not allowed') 56 | }) 57 | 58 | tap.test('throws on sanity.json being invalid (truthy root)', options, async (t) => { 59 | const fixtureDir = path.join(baseFixturesDir, 'disallowed-root-sanity-json') 60 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 61 | t.equal(stdout, '', 'should have empty stdout') 62 | t.equal(exitCode, 1, 'should have exit code 1') 63 | t.match(stderr, '"root" cannot be truthy in a plugin manifest') 64 | }) 65 | 66 | tap.test('throws on sanity.json being invalid (non-object paths)', options, async (t) => { 67 | const fixtureDir = path.join(baseFixturesDir, 'nonobject-sanity-json') 68 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 69 | t.equal(stdout, '', 'should have empty stdout') 70 | t.equal(exitCode, 1, 'should have exit code 1') 71 | t.match(stderr, '"paths" must be an object if declared') 72 | }) 73 | 74 | tap.test('throws on sanity.json being invalid (non-string compiled path)', options, async (t) => { 75 | const fixtureDir = path.join(baseFixturesDir, 'nonstring-compiled-sanity-json') 76 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 77 | t.equal(stdout, '', 'should have empty stdout') 78 | t.equal(exitCode, 1, 'should have exit code 1') 79 | t.match(stderr, '"paths" must have a (string) "compiled" property if declared') 80 | }) 81 | 82 | tap.test('throws on sanity.json being invalid (non-string source path)', options, async (t) => { 83 | const fixtureDir = path.join(baseFixturesDir, 'nonstring-source-sanity-json') 84 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 85 | t.equal(stdout, '', 'should have empty stdout') 86 | t.equal(exitCode, 1, 'should have exit code 1') 87 | t.match(stderr, '"paths" must have a (string) "source" property if declared') 88 | }) 89 | 90 | tap.test('throws on sanity.json being invalid (non-array parts)', options, async (t) => { 91 | const fixtureDir = path.join(baseFixturesDir, 'nonarray-parts-sanity-json') 92 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 93 | t.equal(stdout, '', 'should have empty stdout') 94 | t.equal(exitCode, 1, 'should have exit code 1') 95 | t.match(stderr, '"parts" must be an array if declared') 96 | }) 97 | 98 | tap.test('throws on sanity.json being invalid (non-object part)', options, async (t) => { 99 | const fixtureDir = path.join(baseFixturesDir, 'nonobject-part-sanity-json') 100 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 101 | t.equal(stdout, '', 'should have empty stdout') 102 | t.equal(exitCode, 1, 'should have exit code 1') 103 | t.match(stderr, '"parts[0]" must be an object') 104 | }) 105 | 106 | tap.test('throws on sanity.json being invalid (invalid part)', options, async (t) => { 107 | const fixtureDir = path.join(baseFixturesDir, 'invalid-part-sanity-json') 108 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 109 | t.equal(stdout, '', 'should have empty stdout') 110 | t.equal(exitCode, 1, 'should have exit code 1') 111 | t.match(stderr, 'Keys "name", "path" should be of type string (parts[0])') 112 | }) 113 | 114 | tap.test('throws on sanity.json being invalid (invalid part keys)', options, async (t) => { 115 | const fixtureDir = path.join(baseFixturesDir, 'invalid-part-keys-sanity-json') 116 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 117 | t.equal(stdout, '', 'should have empty stdout') 118 | t.equal(exitCode, 1, 'should have exit code 1') 119 | t.match(stderr, 'Key "unknown" is not allowed in a part declaration (parts[1])') 120 | }) 121 | 122 | tap.test('throws on sanity.json being invalid (unprefixed part)', options, async (t) => { 123 | const fixtureDir = path.join(baseFixturesDir, 'unprefixed-part-sanity-json') 124 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 125 | t.equal(stdout, '', 'should have empty stdout') 126 | t.equal(exitCode, 1, 'should have exit code 1') 127 | t.match( 128 | stderr, 129 | '"name" must be prefixed with "part:unprefixed-part-sanity-json/" - got "some-part-name" (parts[0])' 130 | ) 131 | }) 132 | 133 | tap.test('throws on sanity.json being invalid (unprefixed implementation)', options, async (t) => { 134 | const fixtureDir = path.join(baseFixturesDir, 'unprefixed-implementation-sanity-json') 135 | const {stdout, stderr, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 136 | t.equal(stdout, '', 'should have empty stdout') 137 | t.equal(exitCode, 1, 'should have exit code 1') 138 | t.match(stderr, '"implements" must be prefixed with "part:" - got "some-part-name" (parts[0])') 139 | }) 140 | 141 | tap.test('handles filenames with multiple dots', options, async (t) => { 142 | const fixtureDir = path.join(baseFixturesDir, 'dotted-filename-part-sanity-json') 143 | const {stdout, exitCode} = await execa(sanipack, ['build', fixtureDir], {reject: false}) 144 | t.equal(exitCode, 0, 'should have exit code 1') 145 | t.match(stdout, 'Successfully compiled 1 file with Babel') 146 | }) 147 | -------------------------------------------------------------------------------- /src/sanity/manifest.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const util = require('util') 4 | const pkg = require('../../package.json') 5 | const {buildExtensions} = require('../configs/buildExtensions') 6 | const {hasSourceFile, hasCompiledFile, readJsonFile} = require('../util/files') 7 | const {nullifyError} = require('../util/nullifyError') 8 | 9 | const stat = util.promisify(fs.stat) 10 | const readFile = util.promisify(fs.readFile) 11 | 12 | const allowedPartProps = ['name', 'implements', 'path', 'description'] 13 | const disallowedPluginProps = ['api', 'project', 'plugins', 'env'] 14 | 15 | module.exports = { 16 | getPaths, 17 | readManifest, 18 | validateManifest, 19 | getReferencesPartPaths, 20 | hasSanityJson, 21 | } 22 | 23 | async function getPaths(options = {}) { 24 | const {basePath} = options 25 | const manifest = await readManifest(options) 26 | if (!manifest.paths) { 27 | return null 28 | } 29 | 30 | return absolutifyPaths(manifest.paths, basePath) 31 | } 32 | 33 | function absolutifyPaths(paths, basePath) { 34 | const getPath = (relative) => path.resolve(path.join(basePath, relative)) 35 | return paths 36 | ? { 37 | basePath, 38 | compiled: getPath(paths.compiled), 39 | source: getPath(paths.source), 40 | } 41 | : {basePath} 42 | } 43 | 44 | async function readManifest(options) { 45 | const {basePath, validate = true} = options 46 | const manifestPath = path.normalize(path.join(basePath, 'sanity.json')) 47 | 48 | let content 49 | try { 50 | content = await readFile(manifestPath, 'utf8') 51 | } catch (err) { 52 | if (err.code === 'ENOENT') { 53 | throw new Error( 54 | `No sanity.json found. sanity.json is required for plugins to function. Use \`${pkg.binname} init\` for a new plugin, or create an empty \`sanity.json\` with an empty object (\`{}\`) for existing ones.` 55 | ) 56 | } 57 | 58 | throw new Error(`Failed to read "${manifestPath}": ${err.message}`) 59 | } 60 | 61 | let parsed 62 | try { 63 | parsed = JSON.parse(content) 64 | } catch (err) { 65 | throw new Error(`Error parsing "${manifestPath}": ${err.message}`) 66 | } 67 | 68 | if (validate) { 69 | await validateManifest(parsed, options) 70 | } 71 | 72 | return parsed 73 | } 74 | 75 | async function validateManifest(manifest, opts = {}) { 76 | const options = {isPlugin: true, ...opts} 77 | 78 | if (!isObject(manifest)) { 79 | throw new Error(`Invalid sanity.json: Root must be an object`) 80 | } 81 | 82 | if (options.isPlugin) { 83 | await validatePluginManifest(manifest, options) 84 | } else { 85 | await validateProjectManifest(manifest, options) 86 | } 87 | 88 | if ('root' in manifest && typeof manifest.root !== 'boolean') { 89 | throw new Error(`Invalid sanity.json: "root" property must be a boolean if declared`) 90 | } 91 | 92 | await validateParts(manifest, { 93 | ...options, 94 | paths: absolutifyPaths(manifest.paths, options.basePath), 95 | }) 96 | } 97 | 98 | function validateProjectManifest(manifest, options) { 99 | if ('paths' in manifest) { 100 | throw new Error(`Invalid sanity.json: "paths" property has no meaning in a project manifest`) 101 | } 102 | } 103 | 104 | async function validatePluginManifest(manifest, options) { 105 | const disallowed = Object.keys(manifest) 106 | .filter((key) => disallowedPluginProps.includes(key)) 107 | .map((key) => `"${key}"`) 108 | 109 | if (disallowed.length > 0) { 110 | const plural = disallowed.length > 1 ? 's' : '' 111 | const joined = disallowed.join(', ') 112 | throw new Error( 113 | `Invalid sanity.json: Key${plural} ${joined} ${ 114 | plural ? 'are' : 'is' 115 | } not allowed in a plugin manifest` 116 | ) 117 | } 118 | 119 | if (manifest.root) { 120 | throw new Error(`Invalid sanity.json: "root" cannot be truthy in a plugin manifest`) 121 | } 122 | 123 | await validatePaths(manifest, options) 124 | } 125 | 126 | async function validatePaths(manifest, options) { 127 | if (!('paths' in manifest)) { 128 | return 129 | } 130 | 131 | if (!isObject(manifest.paths)) { 132 | throw new Error(`Invalid sanity.json: "paths" must be an object if declared`) 133 | } 134 | 135 | if (typeof manifest.paths.compiled !== 'string') { 136 | throw new Error( 137 | `Invalid sanity.json: "paths" must have a (string) "compiled" property if declared` 138 | ) 139 | } 140 | 141 | if (typeof manifest.paths.source !== 'string') { 142 | throw new Error( 143 | `Invalid sanity.json: "paths" must have a (string) "source" property if declared` 144 | ) 145 | } 146 | 147 | const sourcePath = path.resolve(options.basePath, manifest.paths.source) 148 | let srcStats 149 | try { 150 | srcStats = await stat(sourcePath) 151 | } catch (err) { 152 | if (err.code === 'ENOENT') { 153 | throw new Error(`sanity.json references "source" path which does not exist: "${sourcePath}"`) 154 | } 155 | } 156 | 157 | if (!srcStats.isDirectory()) { 158 | throw new Error( 159 | `sanity.json references "source" path which is not a directory: "${sourcePath}"` 160 | ) 161 | } 162 | } 163 | 164 | async function validateParts(manifest, options) { 165 | if (!('parts' in manifest)) { 166 | return 167 | } 168 | 169 | if (!Array.isArray(manifest.parts)) { 170 | throw new Error(`Invalid sanity.json: "parts" must be an array if declared`) 171 | } 172 | 173 | let i = 0 174 | for (const part of manifest.parts) { 175 | await validatePart(part, i, options) 176 | i++ 177 | } 178 | } 179 | 180 | async function validatePart(part, index, options) { 181 | if (!isObject(part)) { 182 | throw new Error(`Invalid sanity.json: "parts[${index}]" must be an object`) 183 | } 184 | 185 | validateAllowedPartKeys(part, index) 186 | validatePartStringValues(part, index) 187 | validatePartNames(part, index, options) 188 | await validatePartFiles(part, index, options) 189 | } 190 | 191 | async function validatePartFiles(part, index, options) { 192 | const {verifyCompiledParts, verifySourceParts, paths} = options 193 | if (!part.path) { 194 | return 195 | } 196 | 197 | const ext = path.extname(part.path) 198 | if (paths.source && ext && ext !== '.js' && buildExtensions.includes(ext)) { 199 | throw new Error( 200 | `Invalid sanity.json: Part path has extension which is not applicable after compiling. ${ext} becomes .js after compiling. Specify filename without extension (${path.basename( 201 | part.path 202 | )}) (parts[${index}])` 203 | ) 204 | } 205 | 206 | if (!verifySourceParts && !verifyCompiledParts) { 207 | return 208 | } 209 | 210 | const [srcExists, libExists] = await Promise.all([ 211 | hasSourceFile(part.path, paths), 212 | verifyCompiledParts && hasCompiledFile(part.path, paths), 213 | ]) 214 | 215 | if (!srcExists) { 216 | throw new Error( 217 | `Invalid sanity.json: Part path references file that does not exist in source directory (${ 218 | paths.source || paths.basePath 219 | }) (parts[${index}])` 220 | ) 221 | } 222 | 223 | if (verifyCompiledParts && !libExists) { 224 | throw new Error( 225 | `Invalid sanity.json: Part path references file ("${part.path}") that does not exist in compiled directory (${paths.compiled}) (parts[${index}])` 226 | ) 227 | } 228 | } 229 | 230 | function validatePartNames(part, index, options) { 231 | const pluginName = options.pluginName.replace(/^sanity-plugin-/, '') 232 | if (part.name && !part.name.startsWith(`part:${pluginName}/`)) { 233 | throw new Error( 234 | `Invalid sanity.json: "name" must be prefixed with "part:${pluginName}/" - got "${part.name}" (parts[${index}])` 235 | ) 236 | } 237 | 238 | if (part.implements && !part.implements.startsWith('part:')) { 239 | throw new Error( 240 | `Invalid sanity.json: "implements" must be prefixed with "part:" - got "${part.implements}" (parts[${index}])` 241 | ) 242 | } 243 | } 244 | 245 | function validateAllowedPartKeys(part, index) { 246 | const disallowed = Object.keys(part) 247 | .filter((key) => !allowedPartProps.includes(key)) 248 | .map((key) => `"${key}"`) 249 | 250 | if (disallowed.length > 0) { 251 | const plural = disallowed.length > 1 ? 's' : '' 252 | const joined = disallowed.join(', ') 253 | throw new Error( 254 | `Invalid sanity.json: Key${plural} ${joined} ${ 255 | plural ? 'are' : 'is' 256 | } not allowed in a part declaration (parts[${index}])` 257 | ) 258 | } 259 | } 260 | 261 | function validatePartStringValues(part, index) { 262 | const nonStrings = Object.keys(part) 263 | .filter((key) => typeof part[key] !== 'string') 264 | .map((key) => `"${key}"`) 265 | 266 | if (nonStrings.length > 0) { 267 | const plural = nonStrings.length > 1 ? 's' : '' 268 | const joined = nonStrings.join(', ') 269 | throw new Error( 270 | `Invalid sanity.json: Key${plural} ${joined} should be of type string (parts[${index}])` 271 | ) 272 | } 273 | } 274 | 275 | function isObject(obj) { 276 | return !Array.isArray(obj) && obj !== null && typeof obj === 'object' 277 | } 278 | 279 | function getReferencesPartPaths(manifest, basePath) { 280 | const {paths, parts} = {paths: {}, parts: [], ...manifest} 281 | const compiledPath = path.resolve(basePath, paths.compiled || '') 282 | 283 | return parts 284 | .filter((part) => part.path) 285 | .map((part) => part.path) 286 | .map((partPath) => (path.extname(partPath) === '' ? `${partPath}.js` : partPath)) 287 | .map((partPath) => 288 | path.isAbsolute(partPath) 289 | ? partPath // Not sure if this ever happens, but :shrugs: 290 | : path.resolve(compiledPath, partPath) 291 | ) 292 | } 293 | 294 | async function hasSanityJson(basePath) { 295 | const file = await readJsonFile(path.join(basePath, 'sanity.json')).catch(nullifyError) 296 | return {exists: Boolean(file), isRoot: Boolean(file && file.root)} 297 | } 298 | --------------------------------------------------------------------------------