commit a9acd8a6f767d4531c78f64e6c0818dd796ed2e1 Author: Thomas Allmer Date: Sun Oct 18 15:50:41 2020 +0200 chore: move create into separate repo diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..9ec2e68 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,15 @@ +module.exports = { + extends: [require.resolve('@open-wc/eslint-config'), require.resolve('eslint-config-prettier')], + overrides: [ + { + files: ['**/test/**/*.js', '**/*.config.js'], + rules: { + 'no-console': 'off', + 'no-unused-expressions': 'off', + 'class-methods-use-this': 'off', + 'max-classes-per-file': 'off', + 'import/no-extraneous-dependencies': 'off', // we moved all devDependencies to root + }, + }, + ], +}; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e336dc9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +## editors +/.idea +/.vscode + +## system files +.DS_Store + +## code coverage folders +coverage/ + +## npm +node_modules +npm-debug.log +yarn-error.log + +## temp folders +/.tmp/ + +## we prefer yarn.lock +package-lock.json + +## build output +dist +build-stats.json +stats.html +.rpt2_cache + +## browserstack +local.log diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..f1d5a9a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,1211 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +# [0.36.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.35.0...@open-wc/create@0.36.0) (2020-10-05) + + +### Features + +* **create:** add prepublish script to typescript wc generator ([828adad](https://github.com/open-wc/open-wc/commit/828adadb75327d9870d3be4132e57370e4f61490)) + + + + + +# [0.35.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.34.0...@open-wc/create@0.35.0) (2020-10-04) + + +### Features + +* **create:** update to use @web/test-runner ([#1861](https://github.com/open-wc/open-wc/issues/1861)) ([0bad752](https://github.com/open-wc/open-wc/commit/0bad752609c613bbaed887fe26bc70d0809872cf)) + + + + + +# [0.34.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.33.3...@open-wc/create@0.34.0) (2020-10-03) + + +### Features + +* **create:** update to use @web/dev-server ([#1858](https://github.com/open-wc/open-wc/issues/1858)) ([3383658](https://github.com/open-wc/open-wc/commit/33836581bbf2db98e5815f5f3a066446b201b742)) + + + + + +## [0.33.3](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.33.2...@open-wc/create@0.33.3) (2020-10-01) + +**Note:** Version bump only for package @open-wc/create + + + + + +## [0.33.2](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.33.1...@open-wc/create@0.33.2) (2020-08-27) + +**Note:** Version bump only for package @open-wc/create + + + + + +## [0.33.1](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.33.0...@open-wc/create@0.33.1) (2020-08-19) + +**Note:** Version bump only for package @open-wc/create + + + + + +# [0.33.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.32.5...@open-wc/create@0.33.0) (2020-08-16) + + +### Features + +* support building of multi page applications (mpa) ([a654535](https://github.com/open-wc/open-wc/commit/a65453576c42794958e90b9765000f99117097bd)) + + + + + +## [0.32.5](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.32.4...@open-wc/create@0.32.5) (2020-07-24) + + +### Bug Fixes + +* **create:** upgrade to lint-staged@10 ([#1766](https://github.com/open-wc/open-wc/issues/1766)) ([6913611](https://github.com/open-wc/open-wc/commit/6913611953a569925fa3bb01aed33a7b5757d1da)) + + + + + +## [0.32.4](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.32.3...@open-wc/create@0.32.4) (2020-05-23) + + +### Bug Fixes + +* **create:** use rootDir to maintain file structure ([11c381e](https://github.com/open-wc/open-wc/commit/11c381e202328f3d066dc4349e4605414c35785d)) + + + + + +## [0.32.3](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.32.2...@open-wc/create@0.32.3) (2020-05-20) + + +### Bug Fixes + +* **create:** support number for optionsToCommand ([6fc4298](https://github.com/open-wc/open-wc/commit/6fc42980baf23588d485ff9e3643b6e025ded2dc)) + + + + + +## [0.32.2](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.32.1...@open-wc/create@0.32.2) (2020-05-20) + + +### Bug Fixes + +* **create:** generate sourcemap for ts files ([#1656](https://github.com/open-wc/open-wc/issues/1656)) ([624a90f](https://github.com/open-wc/open-wc/commit/624a90fe421fc501ee2082b86386a4a339ba7dca)) + + + + + +## [0.32.1](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.32.0...@open-wc/create@0.32.1) (2020-05-15) + + +### Bug Fixes + +* **create:** pin ts version ([f405cec](https://github.com/open-wc/open-wc/commit/f405cec5bba294a1427b876aacc031b360932518)) + + + + + +# [0.32.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.31.1...@open-wc/create@0.32.0) (2020-05-06) + + +### Features + +* **create:** support ts in generator ([1ee0b84](https://github.com/open-wc/open-wc/commit/1ee0b848de955e0614e34bc6622441c6bb002974)) + + + + + +## [0.31.1](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.31.0...@open-wc/create@0.31.1) (2020-05-01) + +**Note:** Version bump only for package @open-wc/create + + + + + +# [0.31.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.30.0...@open-wc/create@0.31.0) (2020-04-20) + + +### Features + +* **create:** update prettier to v2 ([d6aa4f9](https://github.com/open-wc/open-wc/commit/d6aa4f9fe0c97c72e6401186cc14d019e8d7ee09)) + + + + + +# [0.30.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.29.0...@open-wc/create@0.30.0) (2020-04-13) + + +### Features + +* **create:** copyTemplates resolves with the copied files ([00a7d90](https://github.com/open-wc/open-wc/commit/00a7d908cd2aa7b59d686c533ef8aaea82f42194)) + + + + + +# [0.29.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.28.4...@open-wc/create@0.29.0) (2020-04-13) + + +### Features + +* **create:** remove webpack option ([2e6083d](https://github.com/open-wc/open-wc/commit/2e6083de7556ed47ef9b8ca791e18dd000c9dd77)) +* **create:** update building-rollup ([7b41b3f](https://github.com/open-wc/open-wc/commit/7b41b3fbf97a637b6d8d4fa63a3852ff6146a92e)) +* **create:** update demoing-storybook ([4300d2e](https://github.com/open-wc/open-wc/commit/4300d2ea627a65e933eb3badcbec5b57d46f2f25)) + + + + + +## [0.28.4](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.28.3...@open-wc/create@0.28.4) (2020-04-12) + +**Note:** Version bump only for package @open-wc/create + + + + + +## [0.28.3](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.28.2...@open-wc/create@0.28.3) (2020-04-12) + +**Note:** Version bump only for package @open-wc/create + + + + + +## [0.28.2](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.28.1...@open-wc/create@0.28.2) (2020-04-05) + + +### Bug Fixes + +* **create:** set default value for variable ([5c39676](https://github.com/open-wc/open-wc/commit/5c3967600837cc9e84dbed6a23772a3c21b67c81)) + + + + + +## [0.28.1](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.28.0...@open-wc/create@0.28.1) (2020-03-24) + +**Note:** Version bump only for package @open-wc/create + + + + + +# [0.28.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.27.0...@open-wc/create@0.28.0) (2020-03-06) + + +### Features + +* **create:** clarify features ([7f9747c](https://github.com/open-wc/open-wc/commit/7f9747cfd9859be44750f359c3dcc6951d08a597)) +* **create:** remove app pages and pseudo router ([b98a4da](https://github.com/open-wc/open-wc/commit/b98a4dadb5290dbaca4cdefd7f5a499adaec654d)) +* **create:** remove default karma browserstack scaffolding ([55c7025](https://github.com/open-wc/open-wc/commit/55c702544db138c54eb39cbddec14e206f05e706)) +* **create:** remove snapshot testing scaffold ([ff5a421](https://github.com/open-wc/open-wc/commit/ff5a4214d5d9d4545c50beb730e8e19c66e05b35)) +* **create:** simplify app output ([0c8cd71](https://github.com/open-wc/open-wc/commit/0c8cd71340470dd6ff7f5930487dc37fb2983415)) + + + + + +# [0.27.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.26.8...@open-wc/create@0.27.0) (2020-03-01) + + +### Bug Fixes + +* **create:** fix race condition with registering addons ([f92509f](https://github.com/open-wc/open-wc/commit/f92509fe0a31b7e8526e9d3c6325aa3567cc11ed)) +* **create:** remove mention of test and start compatibility ([f3f3b98](https://github.com/open-wc/open-wc/commit/f3f3b9809cb36cdc94e5eff8d0e28060bfe941da)) + + +### Features + +* **rollup-plugin-html:** first release ([9acb29a](https://github.com/open-wc/open-wc/commit/9acb29ac84b0ef7e2b06c57043c9d2c76d5a29c0)) + + + + + +## [0.26.8](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.26.7...@open-wc/create@0.26.8) (2020-02-19) + + +### Bug Fixes + +* **create:** update building-rollup due to terser vulnerability ([#1350](https://github.com/open-wc/open-wc/issues/1350)) ([feff11e](https://github.com/open-wc/open-wc/commit/feff11e818d3673fbf9df7b3c31092d2f77be2c4)) + + + + + +## [0.26.7](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.26.6...@open-wc/create@0.26.7) (2020-02-09) + +**Note:** Version bump only for package @open-wc/create + + + + + +## [0.26.6](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.26.5...@open-wc/create@0.26.6) (2020-02-03) + + +### Bug Fixes + +* **create:** update broken @babel/cli ([b0cb95b](https://github.com/open-wc/open-wc/commit/b0cb95b650e3aae3d04ddf1879b5eec62abe7d00)) + + + + + +## [0.26.5](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.26.4...@open-wc/create@0.26.5) (2020-02-02) + +**Note:** Version bump only for package @open-wc/create + + + + + +## [0.26.4](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.26.3...@open-wc/create@0.26.4) (2020-01-15) + + +### Bug Fixes + +* **demoing-storybook:** copy assets for deployed build ([30b998a](https://github.com/open-wc/open-wc/commit/30b998ad6b6e156c6b4bb7e40ae7f06dae8b1083)) + + + + + +## [0.26.3](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.26.2...@open-wc/create@0.26.3) (2019-12-23) + + +### Bug Fixes + +* **generate:** align versions in package.json template ([6a5188d](https://github.com/open-wc/open-wc/commit/6a5188df3a8db2c1b7e169296157b15d13b302d8)) + + + + + +## [0.26.2](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.26.1...@open-wc/create@0.26.2) (2019-12-18) + + +### Bug Fixes + +* **create:** replace webpack-merge by deepmerge in testing dependencies ([e8c0553](https://github.com/open-wc/open-wc/commit/e8c0553de8f083785f21f34d7edbaba17a69492a)) + + + + + +## [0.26.1](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.26.0...@open-wc/create@0.26.1) (2019-12-12) + + +### Bug Fixes + +* **demoing-storybook:** use " for stories glob to support windows ([20d9db0](https://github.com/open-wc/open-wc/commit/20d9db0b7419414aa7f8fa0956834015518fe27f)) + + + + + +# [0.26.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.25.0...@open-wc/create@0.26.0) (2019-12-09) + + +### Features + +* **create:** update building-rollup dependency ([2c83603](https://github.com/open-wc/open-wc/commit/2c836039743356c0b4be02edbae7a6addbeaf8ac)) + + + + + +# [0.25.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.24.4...@open-wc/create@0.25.0) (2019-12-08) + + +### Features + +* **create:** update linting config ([#1090](https://github.com/open-wc/open-wc/issues/1090)) ([795449d](https://github.com/open-wc/open-wc/commit/795449de3e49153004626a648bb59e25dc61bba8)) + + + + + +## [0.24.4](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.24.3...@open-wc/create@0.24.4) (2019-11-27) + +**Note:** Version bump only for package @open-wc/create + + + + + +## [0.24.3](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.24.2...@open-wc/create@0.24.3) (2019-11-24) + +**Note:** Version bump only for package @open-wc/create + + + + + +## [0.24.2](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.24.1...@open-wc/create@0.24.2) (2019-11-24) + + +### Bug Fixes + +* **create:** update building rollup version ([#1039](https://github.com/open-wc/open-wc/issues/1039)) ([8d2e0a8](https://github.com/open-wc/open-wc/commit/8d2e0a89bb5b34b4abaa4c6a5f695037f8cc6f1a)) + + + + + +## [0.24.1](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.24.0...@open-wc/create@0.24.1) (2019-11-24) + +**Note:** Version bump only for package @open-wc/create + + + + + +# [0.24.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.23.0...@open-wc/create@0.24.0) (2019-11-23) + + +### Features + +* **create:** add a11y and snapshot tests ([a128621](https://github.com/open-wc/open-wc/commit/a128621340a8b8c6e89b4a054365f671c00fe9e8)) +* **create:** improve app scaffold formatting ([b4b3233](https://github.com/open-wc/open-wc/commit/b4b32338cff864d1e00e94efd15bc5d8023062ef)) + + + + + +# [0.23.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.22.1...@open-wc/create@0.23.0) (2019-11-20) + + +### Features + +* **create:** align with new storybook ([770cb83](https://github.com/open-wc/open-wc/commit/770cb8326aee788616a5e2b6d950f738598b0518)) + + + + + +## [0.22.1](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.22.0...@open-wc/create@0.22.1) (2019-11-19) + + +### Bug Fixes + +* **create:** adjust storybook config for app generator ([#1003](https://github.com/open-wc/open-wc/issues/1003)) ([de76353](https://github.com/open-wc/open-wc/commit/de76353f76441602071aa73d090457105f110efe)) + + + + + +# [0.22.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.21.5...@open-wc/create@0.22.0) (2019-11-19) + + +### Bug Fixes + +* use es-dev-server auto compatibility ([df6fe21](https://github.com/open-wc/open-wc/commit/df6fe2151b3f22d068f0acd94880a43c1fb828a7)) + + +### Features + +* update to use auto compatibility of es-dev-server ([f6d085e](https://github.com/open-wc/open-wc/commit/f6d085eda5a05391d1a464b9e49222c78194b0d9)) + + + + + +## [0.21.5](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.21.4...@open-wc/create@0.21.5) (2019-11-14) + + +### Bug Fixes + +* **create:** rename directory of page-main test ([84c3607](https://github.com/open-wc/open-wc/commit/84c3607)), closes [#945](https://github.com/open-wc/open-wc/issues/945) [#987](https://github.com/open-wc/open-wc/issues/987) + + + + + +## [0.21.4](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.21.3...@open-wc/create@0.21.4) (2019-11-13) + +**Note:** Version bump only for package @open-wc/create + + + + + +## [0.21.3](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.21.2...@open-wc/create@0.21.3) (2019-11-03) + + +### Bug Fixes + +* **create:** rename packages to components ([#945](https://github.com/open-wc/open-wc/issues/945)) ([6f08241](https://github.com/open-wc/open-wc/commit/6f08241)) + + + + + +## [0.21.2](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.21.1...@open-wc/create@0.21.2) (2019-11-03) + + +### Bug Fixes + +* align versions within the monorepo ([fa2ad9f](https://github.com/open-wc/open-wc/commit/fa2ad9f)) + + + + + +## [0.21.1](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.21.0...@open-wc/create@0.21.1) (2019-11-02) + + +### Bug Fixes + +* **create:** regression in app scaffolding when no options are selected ([#940](https://github.com/open-wc/open-wc/issues/940)) ([dea14cd](https://github.com/open-wc/open-wc/commit/dea14cd)) + + + + + +# [0.21.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.20.1...@open-wc/create@0.21.0) (2019-11-02) + + +### Features + +* **create:** dynamic READMEs ([#919](https://github.com/open-wc/open-wc/issues/919)) ([ca8623f](https://github.com/open-wc/open-wc/commit/ca8623f)) + + + + + +## [0.20.1](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.20.0...@open-wc/create@0.20.1) (2019-10-30) + + +### Bug Fixes + +* **create:** add basic custom-elements.json ([1db9e6e](https://github.com/open-wc/open-wc/commit/1db9e6e)) + + + + + +# [0.20.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.19.2...@open-wc/create@0.20.0) (2019-10-29) + + +### Features + +* **demoing-storybook:** storybook 5.3 with docs mode - see MIGRATION.md ([9000b92](https://github.com/open-wc/open-wc/commit/9000b92)) + + + + + +## [0.19.2](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.19.1...@open-wc/create@0.19.2) (2019-10-25) + + +### Bug Fixes + +* align used mocha version ([#901](https://github.com/open-wc/open-wc/issues/901)) ([3606381](https://github.com/open-wc/open-wc/commit/3606381)) + + + + + +## [0.19.1](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.19.0...@open-wc/create@0.19.1) (2019-10-23) + +**Note:** Version bump only for package @open-wc/create + + + + + +# [0.19.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.18.9...@open-wc/create@0.19.0) (2019-10-13) + + +### Bug Fixes + +* **create:** use standard webpack mode notation ([#839](https://github.com/open-wc/open-wc/issues/839)) ([ad99b17](https://github.com/open-wc/open-wc/commit/ad99b17)) + + +### Features + +* **testing-karma-bs:** add package main ([#714](https://github.com/open-wc/open-wc/issues/714)) ([1754976](https://github.com/open-wc/open-wc/commit/1754976)) + + + + + +## [0.18.9](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.18.8...@open-wc/create@0.18.9) (2019-09-25) + + +### Bug Fixes + +* **create:** don't display style nodes ([#816](https://github.com/open-wc/open-wc/issues/816)) ([b76282a](https://github.com/open-wc/open-wc/commit/b76282a)) + + + + + +## [0.18.8](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.18.7...@open-wc/create@0.18.8) (2019-08-31) + + +### Bug Fixes + +* **create:** bump version of testing to 2.x ([0710fb9](https://github.com/open-wc/open-wc/commit/0710fb9)) + + + + + +## [0.18.7](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.18.6...@open-wc/create@0.18.7) (2019-08-20) + + +### Bug Fixes + +* **create:** change installation pkg manager logs prefix to name ([4e1a0ab](https://github.com/open-wc/open-wc/commit/4e1a0ab)) + + + + + +## [0.18.6](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.18.5...@open-wc/create@0.18.6) (2019-08-20) + + +### Bug Fixes + +* **create:** add eslint dependency in create ([8d26f71](https://github.com/open-wc/open-wc/commit/8d26f71)) + + + + + +## [0.18.5](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.18.4...@open-wc/create@0.18.5) (2019-08-05) + + +### Bug Fixes + +* cleanup package.json scripts ([be6bdb5](https://github.com/open-wc/open-wc/commit/be6bdb5)) + + + + + +## [0.18.4](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.18.3...@open-wc/create@0.18.4) (2019-08-05) + + +### Bug Fixes + +* **create:** allow extending Generator to override name ([#681](https://github.com/open-wc/open-wc/issues/681)) ([c08919b](https://github.com/open-wc/open-wc/commit/c08919b)) + + + + + +## [0.18.3](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.18.2...@open-wc/create@0.18.3) (2019-08-02) + + +### Bug Fixes + +* **create:** allow subclassers to pass custom generator names ([#680](https://github.com/open-wc/open-wc/issues/680)) ([d19b7b9](https://github.com/open-wc/open-wc/commit/d19b7b9)) + + + + + +## [0.18.2](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.18.1...@open-wc/create@0.18.2) (2019-08-01) + + +### Bug Fixes + +* **create:** use compatibility flag in karma bs ([9d186b1](https://github.com/open-wc/open-wc/commit/9d186b1)) + + + + + +## [0.18.1](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.18.0...@open-wc/create@0.18.1) (2019-08-01) + + +### Bug Fixes + +* **create:** add check before overwriting files ([ee469c0](https://github.com/open-wc/open-wc/commit/ee469c0)) + + + + + +# [0.18.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.17.0...@open-wc/create@0.18.0) (2019-08-01) + + +### Features + +* **create:** app creates sub components ([6325861](https://github.com/open-wc/open-wc/commit/6325861)) + + + + + +# [0.17.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.16.0...@open-wc/create@0.17.0) (2019-07-27) + + +### Features + +* **create:** move configs into package.json, add common-repo generator ([f6efb7a](https://github.com/open-wc/open-wc/commit/f6efb7a)) + + + + + +# [0.16.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.15.0...@open-wc/create@0.16.0) (2019-07-26) + + +### Bug Fixes + +* **create:** add index.js entrypoint ([aa66639](https://github.com/open-wc/open-wc/commit/aa66639)) +* **create:** set custom element in root of the package as entrypoint ([9ab084f](https://github.com/open-wc/open-wc/commit/9ab084f)) + + +### Features + +* **create:** ensure that building-rollup/webpack use the latest exports ([b8211c9](https://github.com/open-wc/open-wc/commit/b8211c9)) + + + + + +# [0.15.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.14.0...@open-wc/create@0.15.0) (2019-07-22) + + +### Bug Fixes + +* **create:** update testing-karma and demoing-storybook dependencies ([90a44d0](https://github.com/open-wc/open-wc/commit/90a44d0)) + + +### Features + +* **create:** align outputs of app-lit and wc-lit ([04fe655](https://github.com/open-wc/open-wc/commit/04fe655)) +* **create:** move to a single app generator ([a3d8633](https://github.com/open-wc/open-wc/commit/a3d8633)) + + + + + +# [0.14.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.13.0...@open-wc/create@0.14.0) (2019-07-22) + + +### Features + +* **demoing-storybook:** add a11y addon to package and generator ([#605](https://github.com/open-wc/open-wc/issues/605)) ([60bd5f7](https://github.com/open-wc/open-wc/commit/60bd5f7)) + + + + + +# [0.13.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.12.10...@open-wc/create@0.13.0) (2019-07-12) + + +### Features + +* **create:** switch from owc-dev-server to es-dev-server ([#571](https://github.com/open-wc/open-wc/issues/571)) ([97a80d1](https://github.com/open-wc/open-wc/commit/97a80d1)) + + + + + +## [0.12.10](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.12.9...@open-wc/create@0.12.10) (2019-07-09) + +**Note:** Version bump only for package @open-wc/create + + + + + +## [0.12.9](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.12.8...@open-wc/create@0.12.9) (2019-07-08) + + +### Bug Fixes + +* use file extensions for imports to support import maps ([c711b13](https://github.com/open-wc/open-wc/commit/c711b13)) + + + + + +## [0.12.8](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.12.7...@open-wc/create@0.12.8) (2019-06-23) + + +### Bug Fixes + +* add missing dependencies ([9abf373](https://github.com/open-wc/open-wc/commit/9abf373)) + + + + + +## [0.12.7](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.12.6...@open-wc/create@0.12.7) (2019-06-23) + +**Note:** Version bump only for package @open-wc/create + + + + + +## [0.12.6](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.12.5...@open-wc/create@0.12.6) (2019-06-23) + + +### Bug Fixes + +* **create:** improve clarity of init ([#497](https://github.com/open-wc/open-wc/issues/497)) ([ed5277e](https://github.com/open-wc/open-wc/commit/ed5277e)) + + + + + +## [0.12.5](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.12.4...@open-wc/create@0.12.5) (2019-06-18) + + +### Bug Fixes + +* **create:** set app-index in component demo ([#503](https://github.com/open-wc/open-wc/issues/503)) ([847cb52](https://github.com/open-wc/open-wc/commit/847cb52)) + + + + + +## [0.12.4](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.12.3...@open-wc/create@0.12.4) (2019-06-14) + + +### Bug Fixes + +* align scripts and update create ([#494](https://github.com/open-wc/open-wc/issues/494)) ([96b62c7](https://github.com/open-wc/open-wc/commit/96b62c7)) + + + + + +## [0.12.3](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.12.2...@open-wc/create@0.12.3) (2019-06-05) + + +### Bug Fixes + +* **create:** use correct open path ([02cab4b](https://github.com/open-wc/open-wc/commit/02cab4b)) + + + + + +## [0.12.2](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.12.1...@open-wc/create@0.12.2) (2019-05-20) + + +### Bug Fixes + +* **create:** in wc-lit-element use correct attribute name in demo ([73cc787](https://github.com/open-wc/open-wc/commit/73cc787)) + + + + + +## [0.12.1](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.12.0...@open-wc/create@0.12.1) (2019-05-11) + + +### Bug Fixes + +* **create:** remove plain/direct browser tests use karma watch instead ([eb23c8f](https://github.com/open-wc/open-wc/commit/eb23c8f)) + + + + + +# [0.12.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.11.2...@open-wc/create@0.12.0) (2019-05-11) + + +### Bug Fixes + +* recommend putting index.html into the root folder ([b943f53](https://github.com/open-wc/open-wc/commit/b943f53)) + + +### Features + +* use latest eslint-plugin-lit ([0d90757](https://github.com/open-wc/open-wc/commit/0d90757)) + + + + + +## [0.11.2](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.11.1...@open-wc/create@0.11.2) (2019-05-08) + + +### Bug Fixes + +* **create:** use latest version of testing-karma ([7a68451](https://github.com/open-wc/open-wc/commit/7a68451)) + + + + + +## [0.11.1](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.11.0...@open-wc/create@0.11.1) (2019-05-07) + + +### Bug Fixes + +* **create:** add building-rollup to starter-app ([561f153](https://github.com/open-wc/open-wc/commit/561f153)) + + + + + +# [0.11.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.10.1...@open-wc/create@0.11.0) (2019-05-07) + + +### Features + +* **create:** remove browerslistrc ([1930660](https://github.com/open-wc/open-wc/commit/1930660)) + + + + + +## [0.10.1](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.10.0...@open-wc/create@0.10.1) (2019-05-06) + +**Note:** Version bump only for package @open-wc/create + + + + + +# [0.10.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.9.5...@open-wc/create@0.10.0) (2019-05-06) + + +### Features + +* update to latest testing-karma config syntax ([465bfe0](https://github.com/open-wc/open-wc/commit/465bfe0)) + + + + + +## [0.9.5](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.9.4...@open-wc/create@0.9.5) (2019-05-03) + + +### Bug Fixes + +* **create:** fix tests in barebone-app ([b6a88cc](https://github.com/open-wc/open-wc/commit/b6a88cc)) + + + + + +## [0.9.4](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.9.3...@open-wc/create@0.9.4) (2019-04-28) + + +### Bug Fixes + +* **eslint-config:** loosen up rules for test and stories files ([#408](https://github.com/open-wc/open-wc/issues/408)) ([3fd251e](https://github.com/open-wc/open-wc/commit/3fd251e)) + + + + + +## [0.9.3](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.9.2...@open-wc/create@0.9.3) (2019-04-28) + +**Note:** Version bump only for package @open-wc/create + + + + + +## [0.9.2](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.9.1...@open-wc/create@0.9.2) (2019-04-27) + + +### Bug Fixes + +* **demoing-storybook:** remove warning by setting to use corejs 2 ([b42daba](https://github.com/open-wc/open-wc/commit/b42daba)) + + + + + +## [0.9.1](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.9.0...@open-wc/create@0.9.1) (2019-04-23) + + +### Bug Fixes + +* **create:** add index.html to starter-app generator ([44d412b](https://github.com/open-wc/open-wc/commit/44d412b)) + + + + + +# [0.9.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.8.1...@open-wc/create@0.9.0) (2019-04-16) + + +### Features + +* **create:** show tree of files to create ([aaa5bfb](https://github.com/open-wc/open-wc/commit/aaa5bfb)) + + + + + +## [0.8.1](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.8.0...@open-wc/create@0.8.1) (2019-04-14) + + +### Bug Fixes + +* **create:** fill templateData for upgrade generators ([6140652](https://github.com/open-wc/open-wc/commit/6140652)) + + + + + +# [0.8.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.7.1...@open-wc/create@0.8.0) (2019-04-14) + + +### Features + +* **create:** use prompts package and refactor flow ([16a22be](https://github.com/open-wc/open-wc/commit/16a22be)) + + + + + +## [0.7.1](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.7.0...@open-wc/create@0.7.1) (2019-04-08) + + +### Bug Fixes + +* **create:** update own package versions ([33d8457](https://github.com/open-wc/open-wc/commit/33d8457)) + + + + + +# [0.7.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.6.0...@open-wc/create@0.7.0) (2019-04-08) + + +### Features + +* **semantic-dom-diff:** add support for snapshot testing ([f7a675a](https://github.com/open-wc/open-wc/commit/f7a675a)) + + + + + +# [0.6.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.5.7...@open-wc/create@0.6.0) (2019-04-03) + + +### Features + +* **building-webpack:** enable single entry point html file ([71e5650](https://github.com/open-wc/open-wc/commit/71e5650)) + + + + + +## [0.5.7](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.5.6...@open-wc/create@0.5.7) (2019-04-01) + + +### Bug Fixes + +* **create:** handle windows file pathes as well ([792d7b6](https://github.com/open-wc/open-wc/commit/792d7b6)) +* **create:** use npx for http-server in building-webpack ([bbbc8a1](https://github.com/open-wc/open-wc/commit/bbbc8a1)) + + + + + +## [0.5.6](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.5.5...@open-wc/create@0.5.6) (2019-03-31) + + +### Bug Fixes + +* adopt new karma setup for all packages ([1888260](https://github.com/open-wc/open-wc/commit/1888260)) + + + + + +## [0.5.5](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.5.4...@open-wc/create@0.5.5) (2019-03-28) + + +### Bug Fixes + +* **create:** add browserslistrc ([#331](https://github.com/open-wc/open-wc/issues/331)) ([e6c6924](https://github.com/open-wc/open-wc/commit/e6c6924)) + + + + + +## [0.5.4](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.5.3...@open-wc/create@0.5.4) (2019-03-27) + + +### Bug Fixes + +* **building-webpack:** default webpack generator config and docs ([#321](https://github.com/open-wc/open-wc/issues/321)) ([c4f37a6](https://github.com/open-wc/open-wc/commit/c4f37a6)) + + + + + +## [0.5.3](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.5.2...@open-wc/create@0.5.3) (2019-03-27) + + +### Bug Fixes + +* **create:** fix generator install deps for Windows ([c8bbaf9](https://github.com/open-wc/open-wc/commit/c8bbaf9)) + + + + + +## [0.5.2](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.5.1...@open-wc/create@0.5.2) (2019-03-27) + + +### Bug Fixes + +* **create:** install should only be executed once ([84fb08f](https://github.com/open-wc/open-wc/commit/84fb08f)) + + + + + +## [0.5.1](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.5.0...@open-wc/create@0.5.1) (2019-03-26) + + +### Bug Fixes + +* **create:** fix bug and allow user to choose package manager ([aecc42a](https://github.com/open-wc/open-wc/commit/aecc42a)) + + + + + +# [0.5.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.4.1...@open-wc/create@0.5.0) (2019-03-24) + + +### Bug Fixes + +* **create:** update own versions ([e547f53](https://github.com/open-wc/open-wc/commit/e547f53)) +* adjust generator-open-wc links to create ([cc014b1](https://github.com/open-wc/open-wc/commit/cc014b1)) + + +### Features + +* add type linting generator and info ([0f1d30d](https://github.com/open-wc/open-wc/commit/0f1d30d)) + + + + + +## [0.4.1](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.4.0...@open-wc/create@0.4.1) (2019-03-23) + + +### Bug Fixes + +* **building-rollup:** disable http server caching ([#313](https://github.com/open-wc/open-wc/issues/313)) ([d3ce2b2](https://github.com/open-wc/open-wc/commit/d3ce2b2)) + + + + + +# [0.4.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.3.1...@open-wc/create@0.4.0) (2019-03-21) + + +### Features + +* add version detection ([#306](https://github.com/open-wc/open-wc/issues/306)) ([5724bd7](https://github.com/open-wc/open-wc/commit/5724bd7)) + + + + + +## [0.3.1](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.3.0...@open-wc/create@0.3.1) (2019-03-21) + + +### Bug Fixes + +* **create:** use tagname instead of hardcoded name ([d305f42](https://github.com/open-wc/open-wc/commit/d305f42)) + + + + + +# [0.3.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.2.0...@open-wc/create@0.3.0) (2019-03-20) + + +### Features + +* add rollup starter-app ([#298](https://github.com/open-wc/open-wc/issues/298)) ([ad9bb59](https://github.com/open-wc/open-wc/commit/ad9bb59)) + + + + + +# [0.2.0](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.1.3...@open-wc/create@0.2.0) (2019-03-18) + + +### Features + +* **create:** add building-rollup generator ([2fa1825](https://github.com/open-wc/open-wc/commit/2fa1825)) + + + + + +## [0.1.3](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.1.2...@open-wc/create@0.1.3) (2019-03-17) + +**Note:** Version bump only for package @open-wc/create + + + + + +## [0.1.2](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.1.1...@open-wc/create@0.1.2) (2019-03-13) + + +### Bug Fixes + +* **create:** generated prettier scripts should work on windows ([438a319](https://github.com/open-wc/open-wc/commit/438a319)) + + + + + +## [0.1.1](https://github.com/open-wc/open-wc/compare/@open-wc/create@0.1.0...@open-wc/create@0.1.1) (2019-03-10) + + +### Bug Fixes + +* add cli options ([#276](https://github.com/open-wc/open-wc/issues/276)) ([55af02e](https://github.com/open-wc/open-wc/commit/55af02e)) + + + + + +# 0.1.0 (2019-03-08) + + +### Features + +* add npm init [@open-wc](https://github.com/open-wc) ([4ba6cf1](https://github.com/open-wc/open-wc/commit/4ba6cf1)) diff --git a/README.md b/README.md new file mode 100644 index 0000000..3adea8c --- /dev/null +++ b/README.md @@ -0,0 +1,99 @@ +--- +permalink: 'init/index.html' +title: Create Open Web Components +section: guides +tags: + - guides +--- + +# Create Open Web Components + +Web component project scaffolding. + +[//]: # 'AUTO INSERT HEADER PREPUBLISH' + +## Usage + +```bash +npm init @open-wc +``` + +

WARNING

npm init requires node 10 & npm 6 or higher

+ +This will kickstart a menu guiding you through all available actions. + +``` +$ npm init @open-wc +npx: installed 14 in 4.074s + _.,,,,,,,,,._ + .d'' ``b. Open Web Components Recommendations + .p' Open `q. + .d' Web Components `b. Start or upgrade your web component project with + .d' `b. ease. All our recommendations at your fingertips. + :: ................. :: + `p. .q' See more details at https://open-wc.org/init/ + `p. open-wc.org .q' + `b. @openWc .d' + `q.. ..,' Note: you can exit any time with Ctrl+C or Esc + '',,,,,,,,,,'' + + +? What would you like to do today? › - Use arrow-keys. Return to submit. +❯ Scaffold a new project + Upgrade an existing project +``` + +Our generators are very modular you can pick and choose as you see fit. + +## Scaffold generators + +These generators help you kickstart a new app or web component. +They will create a new folder and set up everything you need to get started immediately. + +Example usage: + +```bash +npm init @open-wc +# Select "Scaffold a new project" +``` + +### Available scaffold generators: + +- `Web Component`
+ This generator scaffolds a starting point for a web component. We recommend using this generator when you want to develop and publish a single web component. +
+ +- `Application`
+ This generator scaffolds a new starter application. We recommend using this generator at the start of your web component project. +
+ +## Features + +The above generators are the perfect playgrounds to prototype. +Add linting, testing, demoing and building whenever the need arises. + +Example usage: + +```bash +cd existing-web-component +npm init @open-wc +# select "Upgrade an existing project" or add features while scaffolding +``` + +### Available Upgrade features + +- `Linting`
+ This generator adds a complete linting setup with ESLint, Prettier, Husky and commitlint. +
+ +- `Testing`
+ This generator adds a complete testing setup with Web Test Runner. +
+ +- `Demoing`
+ This generator adds a complete demoing setup with Storybook. +
+ +- `Building`
+ This generator adds a complete building setup with rollup. +
diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..fc0eb1e --- /dev/null +++ b/babel.config.js @@ -0,0 +1,16 @@ +module.exports = { + plugins: ['babel-plugin-transform-dynamic-import'], + ignore: ['./src/generators/*/templates/**/*'], + presets: [ + [ + '@babel/env', + { + targets: { + node: '10', + }, + corejs: 2, + useBuiltIns: 'usage', + }, + ], + ], +}; diff --git a/owc-app/.editorconfig b/owc-app/.editorconfig new file mode 100644 index 0000000..c8c2d2a --- /dev/null +++ b/owc-app/.editorconfig @@ -0,0 +1,29 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + + +[*] + +# Change these settings to your own preference +indent_style = space +indent_size = 2 + +# We recommend you to keep these unchanged +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false + +[*.json] +indent_size = 2 + +[*.{html,js,md}] +block_comment_start = /** +block_comment = * +block_comment_end = */ diff --git a/owc-app/.gitignore b/owc-app/.gitignore new file mode 100644 index 0000000..f3d7ea0 --- /dev/null +++ b/owc-app/.gitignore @@ -0,0 +1,20 @@ +## editors +/.idea +/.vscode + +## system files +.DS_Store + +## npm +/node_modules/ +/npm-debug.log + +## testing +/coverage/ + +## temp folders +/.tmp/ + +# build +/_site/ +/dist/ diff --git a/owc-app/LICENSE b/owc-app/LICENSE new file mode 100644 index 0000000..7246e5a --- /dev/null +++ b/owc-app/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 owc-app + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/owc-app/README.md b/owc-app/README.md new file mode 100644 index 0000000..f62e851 --- /dev/null +++ b/owc-app/README.md @@ -0,0 +1,30 @@ +

+ +

+ +## Open-wc Starter App + +[![Built with open-wc recommendations](https://img.shields.io/badge/built%20with-open--wc-blue.svg)](https://github.com/open-wc) + +## Quickstart + +To get started: + +```bash +npm init @open-wc +# requires node 10 & npm 6 or higher +``` + +## Scripts + +- `start` runs your app for development, reloading on file changes +- `start:build` runs your app after it has been built using the build command +- `build` builds your app and outputs it in your `dist` directory +- `test` runs your test suite with Web Test Runner +- `lint` runs the linter for your project + +## Tooling configs + +For most of the tools, the configuration is in the `package.json` to reduce the amount of files in your project. + +If you customize the configuration a lot, you can consider moving them to individual files. diff --git a/owc-app/custom-elements.json b/owc-app/custom-elements.json new file mode 100644 index 0000000..c59cca7 --- /dev/null +++ b/owc-app/custom-elements.json @@ -0,0 +1,26 @@ +{ + "version": 2, + "tags": [ + { + "name": "owc-app", + "description": "An application with a title and an action counter", + "properties": [ + { + "name": "title", + "type": "String", + "description": "The title of your application", + "default": "Hey there" + }, + { + "name": "page", + "type": "String", + "description": "Which page to show", + "default": "main" + } + ], + "events": [], + "slots": [], + "cssProperties": [] + } + ] +} diff --git a/owc-app/index.html b/owc-app/index.html new file mode 100644 index 0000000..d39c546 --- /dev/null +++ b/owc-app/index.html @@ -0,0 +1,28 @@ + + + + + + + + + + + owc-app + + + + + + + + + \ No newline at end of file diff --git a/owc-app/package.json b/owc-app/package.json new file mode 100644 index 0000000..0074ee9 --- /dev/null +++ b/owc-app/package.json @@ -0,0 +1,49 @@ +{ + "name": "owc-app", + "version": "0.0.0", + "description": "Webcomponent owc-app following open-wc recommendations", + "license": "MIT", + "author": "owc-app", + "scripts": { + "format": "npm run format:eslint && npm run format:prettier", + "format:eslint": "eslint --ext .js,.html . --fix --ignore-path .gitignore", + "format:prettier": "prettier \"**/*.js\" --write --ignore-path .gitignore", + "lint": "npm run lint:eslint && npm run lint:prettier", + "lint:eslint": "eslint --ext .js,.html . --ignore-path .gitignore", + "lint:prettier": "prettier \"**/*.js\" --check --ignore-path .gitignore", + "start": "web-dev-server --app-index index.html --node-resolve --open --watch" + }, + "dependencies": { + "lit-element": "^2.0.1", + "lit-html": "^1.0.0" + }, + "devDependencies": { + "@open-wc/eslint-config": "^2.0.0", + "@web/dev-server": "^0.0.12", + "husky": "^1.0.0", + "lint-staged": "^10.0.0", + "prettier": "^2.0.4" + }, + "eslintConfig": { + "extends": [ + "@open-wc/eslint-config", + "eslint-config-prettier" + ] + }, + "husky": { + "hooks": { + "pre-commit": "lint-staged" + } + }, + "lint-staged": { + "*.js": [ + "eslint --fix", + "prettier --write", + "git add" + ] + }, + "prettier": { + "singleQuote": true, + "arrowParens": "avoid" + } +} diff --git a/owc-app/src/OwcApp.js b/owc-app/src/OwcApp.js new file mode 100644 index 0000000..98460d9 --- /dev/null +++ b/owc-app/src/OwcApp.js @@ -0,0 +1,84 @@ +import { LitElement, html, css } from 'lit-element'; +import { openWcLogo } from './open-wc-logo.js'; + +export class OwcApp extends LitElement { + static get properties() { + return { + title: { type: String }, + page: { type: String }, + }; + } + + static get styles() { + return css` + :host { + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + font-size: calc(10px + 2vmin); + color: #1a2b42; + max-width: 960px; + margin: 0 auto; + text-align: center; + } + + main { + flex-grow: 1; + } + + .logo > svg { + margin-top: 36px; + animation: app-logo-spin infinite 20s linear; + } + + @keyframes app-logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } + } + + .app-footer { + font-size: calc(12px + 0.5vmin); + align-items: center; + } + + .app-footer a { + margin-left: 5px; + } + `; + } + + render() { + return html` +
+ +

My app

+ +

Edit src/OwcApp.js and save to reload.

+ + Code examples + +
+ + + `; + } +} diff --git a/owc-app/src/open-wc-logo.js b/owc-app/src/open-wc-logo.js new file mode 100644 index 0000000..858bade --- /dev/null +++ b/owc-app/src/open-wc-logo.js @@ -0,0 +1,33 @@ +import { html } from 'lit-html'; + +export const openWcLogo = html` + + + + + + + + + + + +`; diff --git a/owc-app/src/owc-app.js b/owc-app/src/owc-app.js new file mode 100644 index 0000000..9edd11b --- /dev/null +++ b/owc-app/src/owc-app.js @@ -0,0 +1,3 @@ +import { OwcApp } from './OwcApp.js'; + +customElements.define('owc-app', OwcApp); diff --git a/package.json b/package.json new file mode 100644 index 0000000..18743a7 --- /dev/null +++ b/package.json @@ -0,0 +1,61 @@ +{ + "name": "@open-wc/create", + "version": "0.36.0", + "publishConfig": { + "access": "public" + }, + "description": "Easily setup all the tools of Open Web Components.", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/open-wc/open-wc.git", + "directory": "packages/create" + }, + "author": "open-wc", + "homepage": "https://github.com/open-wc/open-wc/tree/master/packages/create", + "bin": { + "create-open-wc": "./dist/create.js" + }, + "scripts": { + "build": "rm -rf dist && babel src --out-dir dist --copy-files --include-dotfiles", + "prepublishOnly": "npm run build && ../../scripts/insert-header.js", + "start": "npm run build && node ./dist/create.js", + "test": "npm run test:node", + "test:node": "mocha --require @babel/register", + "test:update-snapshots": "node -r @babel/register ./test/update-snapshots.js", + "test:watch": "onchange 'src/**/*.js' 'test/**/*.js' -- npm run test --silent" + }, + "files": [ + "dist" + ], + "keywords": [ + "open-wc", + "owc", + "generator", + "starter-app" + ], + "dependencies": { + "chalk": "^2.4.2", + "command-line-args": "^5.0.2", + "dedent": "^0.7.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "prompts": "^2.1.0", + "semver": "^6.1.0" + }, + "devDependencies": { + "@babel/cli": "^7.8.4", + "@babel/core": "^7.11.1", + "@babel/preset-env": "^7.9.0", + "@babel/register": "^7.9.0", + "@open-wc/building-rollup": "^1.9.3", + "@open-wc/eslint-config": "^3.0.0", + "babel-plugin-transform-dynamic-import": "^2.1.0", + "chai": "^4.2.0", + "chai-fs": "^2.0.0", + "eslint": "^7.11.0", + "eslint-config-prettier": "^6.13.0", + "mocha": "^6.2.2", + "onchange": "^5.2.0" + } +} diff --git a/src/Generator.js b/src/Generator.js new file mode 100644 index 0000000..1690c3f --- /dev/null +++ b/src/Generator.js @@ -0,0 +1,121 @@ +/* eslint-disable no-console, import/no-cycle */ +import prompts from 'prompts'; +import path from 'path'; + +import { + copyTemplates, + copyTemplate, + copyTemplateJsonInto, + installNpm, + writeFilesToDisk, + optionsToCommand, +} from './core.js'; + +/** + * Options for the generator + * @typedef {object} GeneratorOptions + * @property {string} [tagName] the dash-case tag name + * @property {string} [destinationPath='auto'] path to output to. default value 'auto' will output to current working directory + * @property {'scaffold'} [type='scaffold'] path to output to. default value 'auto' will output to current working directory + * @property {'true'|'false'} [writeToDisk] whether to write to disk + * @property {'yarn'|'npm'|'false'} [installDependencies] whether and with which tool to install dependencies + */ + +/** + * dash-case to PascalCase + * @param {string} tagName dash-case tag name + * @return {string} PascalCase class name + */ +function getClassName(tagName) { + return tagName + .split('-') + .reduce((previous, part) => previous + part.charAt(0).toUpperCase() + part.slice(1), ''); +} + +class Generator { + constructor() { + /** + * @type {GeneratorOptions} + */ + this.options = { + destinationPath: 'auto', + }; + this.templateData = {}; + this.wantsNpmInstall = true; + this.wantsWriteToDisk = true; + this.wantsRecreateInfo = true; + this.generatorName = '@open-wc'; + } + + execute() { + if (this.options.tagName) { + const { tagName } = this.options; + const className = getClassName(tagName); + this.templateData = { ...this.templateData, tagName, className }; + + if (this.options.destinationPath === 'auto') { + this.options.destinationPath = process.cwd(); + if (this.options.type === 'scaffold') { + this.options.destinationPath = path.join(process.cwd(), tagName); + } + } + } + } + + destinationPath(destination = '') { + return path.join(this.options.destinationPath, destination); + } + + copyTemplate(from, to) { + copyTemplate(from, to, this.templateData); + } + + copyTemplateJsonInto(from, to, options = { mode: 'merge' }) { + copyTemplateJsonInto(from, to, this.templateData, options); + } + + async copyTemplates(from, to = this.destinationPath()) { + return copyTemplates(from, to, this.templateData); + } + + async end() { + if (this.wantsWriteToDisk) { + this.options.writeToDisk = await writeFilesToDisk(); + } + + if (this.wantsNpmInstall) { + const answers = await prompts( + [ + { + type: 'select', + name: 'installDependencies', + message: 'Do you want to install dependencies?', + choices: [ + { title: 'No', value: 'false' }, + { title: 'Yes, with yarn', value: 'yarn' }, + { title: 'Yes, with npm', value: 'npm' }, + ], + }, + ], + { + onCancel: () => { + process.exit(); + }, + }, + ); + this.options.installDependencies = answers.installDependencies; + const { installDependencies } = this.options; + if (installDependencies === 'yarn' || installDependencies === 'npm') { + await installNpm(this.options.destinationPath, installDependencies); + } + } + + if (this.wantsRecreateInfo) { + console.log(''); + console.log('If you want to rerun this exact same generator you can do so by executing:'); + console.log(optionsToCommand(this.options, this.generatorName)); + } + } +} + +export default Generator; diff --git a/src/core.js b/src/core.js new file mode 100644 index 0000000..c8e379e --- /dev/null +++ b/src/core.js @@ -0,0 +1,430 @@ +/* eslint-disable no-console, import/no-cycle */ + +import { spawn } from 'child_process'; +import deepmerge from 'deepmerge'; +import fs from 'fs'; +import glob from 'glob'; +import path from 'path'; +import prompts from 'prompts'; +import Generator from './Generator.js'; + +/** + * + * @param {Function[]} mixins + * @param {typeof Generator} Base + */ +export async function executeMixinGenerator(mixins, options = {}, Base = Generator) { + class Start extends Base {} + mixins.forEach(mixin => { + // @ts-ignore + // eslint-disable-next-line no-class-assign + Start = mixin(Start); + }); + + // class Do extends mixins(Base) {} + const inst = new Start(); + inst.options = { ...inst.options, ...options }; + + await inst.execute(); + if (!options.noEnd) { + await inst.end(); + } +} + +export const virtualFiles = []; + +export function resetVirtualFiles() { + virtualFiles.length = 0; +} + +/** + * Minimal template system. + * Replaces <%= name %> if provides as template + * + * @example + * processTemplate('prefix <%= name %> suffix', { name: 'foo' }) + * // prefix foo suffix + * + * @param {string} _fileContent Template as a string + * @param {object} data Object of all the variables to repalce + * @returns {string} Template with all replacements + */ +export function processTemplate(_fileContent, data = {}) { + let fileContent = _fileContent; + Object.keys(data).forEach(key => { + fileContent = fileContent.replace(new RegExp(`<%= ${key} %>`, 'g'), data[key]); + }); + return fileContent; +} + +/** + * Minimal virtual file system + * Stores files to write in an array + * + * @param {string} filePath + * @param {string} content + */ +export function writeFileToPath(filePath, content) { + let addNewFile = true; + virtualFiles.forEach((fileMeta, index) => { + if (fileMeta.path === filePath) { + virtualFiles[index].content = content; + addNewFile = false; + } + }); + if (addNewFile === true) { + virtualFiles.push({ path: filePath, content }); + } +} + +/** + * + * @param {string} filePath + */ +export function readFileFromPath(filePath) { + let content = false; + virtualFiles.forEach((fileMeta, index) => { + if (fileMeta.path === filePath) { + // eslint-disable-next-line prefer-destructuring + content = virtualFiles[index].content; + } + }); + if (content) { + return content; + } + if (fs.existsSync(filePath)) { + return fs.readFileSync(filePath, 'utf-8'); + } + return false; +} + +/** + * + * @param {string} filePath + */ +export function deleteVirtualFile(filePath) { + const index = virtualFiles.findIndex(fileMeta => fileMeta.path === filePath); + if (index !== -1) { + virtualFiles.splice(index, 1); + } +} + +let overwriteAllFiles = false; + +/** + * + * @param {boolean} value + */ +export function setOverrideAllFiles(value) { + overwriteAllFiles = value; +} + +/** + * + * @param {string} toPath + * @param {string} fileContent + * @param {object} obj Options + */ +export async function writeFileToPathOnDisk( + toPath, + fileContent, + { override = false, ask = true } = {}, +) { + const toPathDir = path.dirname(toPath); + if (!fs.existsSync(toPathDir)) { + fs.mkdirSync(toPathDir, { recursive: true }); + } + if (fs.existsSync(toPath)) { + if (override || overwriteAllFiles) { + fs.writeFileSync(toPath, fileContent); + } else if (ask) { + let wantOverride = overwriteAllFiles; + if (!wantOverride) { + const answers = await prompts( + [ + { + type: 'select', + name: 'overwriteFile', + message: `Do you want to overwrite ${toPath}?`, + choices: [ + { title: 'Yes', value: 'true' }, + { + title: 'Yes for all files', + value: 'always', + }, + { title: 'No', value: 'false' }, + ], + }, + ], + { + onCancel: () => { + process.exit(); + }, + }, + ); + if (answers.overwriteFile === 'always') { + setOverrideAllFiles(true); + wantOverride = true; + } + if (answers.overwriteFile === 'true') { + wantOverride = true; + } + } + if (wantOverride) { + fs.writeFileSync(toPath, fileContent); + } + } + } else { + fs.writeFileSync(toPath, fileContent); + } +} + +/** + * @param {String[]} allFiles pathes to files + * @param {Number} [level] internal to track nesting level + */ +export function filesToTree(allFiles, level = 0) { + const files = allFiles.filter(file => !file.includes('/')); + const dirFiles = allFiles.filter(file => file.includes('/')); + + let indent = ''; + for (let i = 1; i < level; i += 1) { + indent += '│ '; + } + + let output = ''; + const processed = []; + + if (dirFiles.length > 0) { + dirFiles.forEach(dirFile => { + if (!processed.includes(dirFile)) { + const dir = `${dirFile.split('/').shift()}/`; + const subFiles = []; + allFiles.forEach(file => { + if (file.startsWith(dir)) { + subFiles.push(file.substr(dir.length)); + processed.push(file); + } + }); + output += level === 0 ? `${dir}\n` : `${indent}├── ${dir}\n`; + output += filesToTree(subFiles, level + 1); + } + }); + } + + if (files.length === 1) { + output += `${indent}└── ${files[0]}\n`; + } + if (files.length > 1) { + const last = files.pop(); + output += `${indent}├── `; + output += files.join(`\n${indent}├── `); + output += `\n${indent}└── ${last}\n`; + } + return output; +} + +/** + * + */ +export async function writeFilesToDisk() { + const treeFiles = []; + const root = process.cwd(); + virtualFiles.sort((a, b) => { + const pathA = a.path.toLowerCase(); + const pathB = b.path.toLowerCase(); + if (pathA < pathB) return -1; + if (pathA > pathB) return 1; + return 0; + }); + + virtualFiles.forEach(vFile => { + if (vFile.path.startsWith(root)) { + let vFilePath = './'; + vFilePath += vFile.path.substr(root.length + 1); + treeFiles.push(vFilePath); + } + }); + + console.log(''); + console.log(filesToTree(treeFiles)); + + const answers = await prompts( + [ + { + type: 'select', + name: 'writeToDisk', + message: 'Do you want to write this file structure to disk?', + choices: [ + { title: 'Yes', value: 'true' }, + { title: 'No', value: 'false' }, + ], + }, + ], + { + onCancel: () => { + process.exit(); + }, + }, + ); + + if (answers.writeToDisk === 'true') { + // eslint-disable-next-line no-restricted-syntax + for (const fileMeta of virtualFiles) { + // eslint-disable-next-line no-await-in-loop + await writeFileToPathOnDisk(fileMeta.path, fileMeta.content); + } + console.log('Writing..... done'); + } + + return answers.writeToDisk; +} + +export function optionsToCommand(options, generatorName = '@open-wc') { + let command = `npm init ${generatorName} `; + Object.keys(options).forEach(key => { + const value = options[key]; + if (typeof value === 'string' || typeof value === 'number') { + command += `--${key} ${value} `; + } else if (typeof value === 'boolean' && value === true) { + command += `--${key} `; + } else if (Array.isArray(value)) { + command += `--${key} ${value.join(' ')} `; + } + }); + return command; +} + +/** + * + * @param {string} fromPath + * @param {string} toPath + * @param {object} data + */ +export function copyTemplate(fromPath, toPath, data) { + const fileContent = readFileFromPath(fromPath); + if (fileContent) { + const processed = processTemplate(fileContent, data); + writeFileToPath(toPath, processed); + } +} + +/** + * + * @param {string} fromGlob + * @param {string} [toDir] Directory to copy into + * @param {object} data Replace parameters in files + */ +export function copyTemplates(fromGlob, toDir = process.cwd(), data = {}) { + return new Promise(resolve => { + glob(fromGlob, { dot: true }, (er, files) => { + const copiedFiles = []; + files.forEach(filePath => { + if (!fs.lstatSync(filePath).isDirectory()) { + const fileContent = readFileFromPath(filePath); + if (fileContent !== false) { + const processed = processTemplate(fileContent, data); + + // find path write to (force / also on windows) + const replace = path.join(fromGlob.replace(/\*/g, '')).replace(/\\(?! )/g, '/'); + const toPath = filePath.replace(replace, `${toDir}/`); + + copiedFiles.push({ toPath, processed }); + writeFileToPath(toPath, processed); + } + } + }); + resolve(copiedFiles); + }); + }); +} + +/** + * + * @param {string} fromPath + * @param {string} toPath + * @param {object} data + */ +export function copyTemplateJsonInto( + fromPath, + toPath, + data = {}, + { mode = 'merge' } = { mode: 'merge' }, +) { + const content = readFileFromPath(fromPath); + if (content === false) { + return; + } + const processed = processTemplate(content, data); + const mergeMeObj = JSON.parse(processed); + + const overwriteMerge = (destinationArray, sourceArray) => sourceArray; + + const emptyTarget = value => (Array.isArray(value) ? [] : {}); + const clone = (value, options) => deepmerge(emptyTarget(value), value, options); + + const combineMerge = (target, source, options) => { + const destination = target.slice(); + + source.forEach((item, index) => { + if (typeof destination[index] === 'undefined') { + const cloneRequested = options.clone !== false; + const shouldClone = cloneRequested && options.isMergeableObject(item); + destination[index] = shouldClone ? clone(item, options) : item; + } else if (options.isMergeableObject(item)) { + destination[index] = deepmerge(target[index], item, options); + } else if (target.indexOf(item) === -1) { + destination.push(item); + } + }); + return destination; + }; + + const mergeOptions = { arrayMerge: combineMerge }; + if (mode === 'override') { + mergeOptions.arrayMerge = overwriteMerge; + } + + let finalObj = mergeMeObj; + const sourceContent = readFileFromPath(toPath); + if (sourceContent) { + finalObj = deepmerge(JSON.parse(sourceContent), finalObj, mergeOptions); + } + + writeFileToPath(toPath, JSON.stringify(finalObj, null, 2)); +} + +/** + * @param {string} command + * @param {object} options + */ +function _install(command = 'npm', options) { + return new Promise(resolve => { + const install = spawn(command, ['install'], options); + install.stdout.on('data', data => { + console.log(`${data}`.trim()); + }); + + install.stderr.on('data', data => { + console.log(`${command}: ${data}`); + }); + + install.on('close', () => { + resolve(); + }); + }); +} + +/** + * + * @param {string} where + * @param {string} command + */ +export async function installNpm(where, command) { + console.log(''); + console.log('Installing dependencies...'); + console.log('This might take some time...'); + console.log(`Using ${command} to install...`); + await _install(command, { cwd: where, shell: true }); + console.log(''); +} diff --git a/src/create.js b/src/create.js new file mode 100644 index 0000000..a057c4c --- /dev/null +++ b/src/create.js @@ -0,0 +1,26 @@ +#!/usr/bin/env node + +/* eslint-disable no-console */ + +import semver from 'semver'; +import chalk from 'chalk'; +import { executeMixinGenerator } from './core.js'; +import { AppMixin } from './generators/app/index.js'; + +(async () => { + try { + if (semver.lte(process.version, '10.12.0')) { + console.log(chalk.bgRed('\nUh oh! Looks like you dont have Node v10.12.0 installed!\n')); + console.log(`You can do this by going to ${chalk.underline.blue(`https://nodejs.org/`)} + +Or if you use nvm: + $ nvm install node ${chalk.gray(`# "node" is an alias for the latest version`)} + $ nvm use node +`); + } else { + await executeMixinGenerator([AppMixin]); + } + } catch (err) { + console.log(err); + } +})(); diff --git a/src/generators/app-lit-element-ts/index.js b/src/generators/app-lit-element-ts/index.js new file mode 100644 index 0000000..8b8a350 --- /dev/null +++ b/src/generators/app-lit-element-ts/index.js @@ -0,0 +1,81 @@ +import { CommonRepoMixin } from '../common-repo/index.js'; + +/* eslint-disable no-console */ +export const TsAppLitElementMixin = subclass => + class extends CommonRepoMixin(subclass) { + async execute() { + await super.execute(); + + const { tagName, className } = this.templateData; + + // write & rename el class template + this.copyTemplate( + `${__dirname}/templates/_my-app.ts`, + this.destinationPath(`src//${tagName}.ts`), + ); + + this.copyTemplate( + `${__dirname}/templates/_MyApp.ts`, + this.destinationPath(`src/${className}.ts`), + ); + + this.copyTemplate( + `${__dirname}/templates/_open-wc-logo.ts`, + this.destinationPath(`src/open-wc-logo.ts`), + ); + + this.copyTemplateJsonInto( + `${__dirname}/templates/_package.json`, + this.destinationPath('package.json'), + ); + + this.copyTemplate( + `${__dirname}/templates/_tsconfig.json`, + this.destinationPath('tsconfig.json'), + ); + + await this.copyTemplates(`${__dirname}/templates/static/**/*`); + + this.copyTemplate( + `${__dirname}/templates/custom-elements.json`, + this.destinationPath('custom-elements.json'), + ); + + if (this.options.features && this.options.features.includes('testing')) { + await this.copyTemplates(`${__dirname}/templates/static-testing/**/*`); + } + + if (this.options.features && this.options.features.includes('demoing')) { + await this.copyTemplates(`${__dirname}/templates/static-demoing/**/*`); + } + + if (this.options.scaffoldFilesFor && this.options.scaffoldFilesFor.includes('demoing')) { + this.copyTemplate( + `${__dirname}/templates/_my-app.stories.ts`, + this.destinationPath(`./stories/${tagName}.stories.ts`), + ); + + await this.copyTemplates(`${__dirname}/templates/static-scaffold-demoing/**/*`); + } + + if (this.options.scaffoldFilesFor && this.options.scaffoldFilesFor.includes('testing')) { + this.copyTemplate( + `${__dirname}/templates/_my-app.test.ts`, + this.destinationPath(`./test/${tagName}.test.ts`), + ); + + await this.copyTemplates(`${__dirname}/templates/static-scaffold-testing/**/*`); + } + } + + async end() { + await super.end(); + console.log(''); + console.log('You are all set up now!'); + console.log(''); + console.log('All you need to do is run:'); + console.log(` cd ${this.templateData.tagName}`); + console.log(' npm run start'); + console.log(''); + } + }; diff --git a/src/generators/app-lit-element-ts/templates/_MyApp.ts b/src/generators/app-lit-element-ts/templates/_MyApp.ts new file mode 100644 index 0000000..caad176 --- /dev/null +++ b/src/generators/app-lit-element-ts/templates/_MyApp.ts @@ -0,0 +1,80 @@ +import { LitElement, html, css, property } from 'lit-element'; +import { openWcLogo } from './open-wc-logo.js'; + +export class <%= className %> extends LitElement { + + @property({type: String}) page = 'main'; + + @property({type: String}) title = ''; + + static styles = css` + :host { + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + font-size: calc(10px + 2vmin); + color: #1a2b42; + max-width: 960px; + margin: 0 auto; + text-align: center; + } + + main { + flex-grow: 1; + } + + .logo > svg { + margin-top: 36px; + animation: app-logo-spin infinite 20s linear; + } + + @keyframes app-logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } + } + + .app-footer { + font-size: calc(12px + 0.5vmin); + align-items: center; + } + + .app-footer a { + margin-left: 5px; + } + `; + + render() { + return html` +
+ +

My app

+ +

Edit src/<%= className %>.js and save to reload.

+ + Code examples + +
+ + + `; + } +} diff --git a/src/generators/app-lit-element-ts/templates/_my-app.stories.ts b/src/generators/app-lit-element-ts/templates/_my-app.stories.ts new file mode 100644 index 0000000..ef6b3ab --- /dev/null +++ b/src/generators/app-lit-element-ts/templates/_my-app.stories.ts @@ -0,0 +1,11 @@ +import { html } from 'lit-html'; +import '../src/<%= tagName %>.js'; + +export default { + title: '<%= tagName %>', +}; + +export const App = () => + html` + <<%= tagName %>>> + `; diff --git a/src/generators/app-lit-element-ts/templates/_my-app.test.ts b/src/generators/app-lit-element-ts/templates/_my-app.test.ts new file mode 100644 index 0000000..e21bc3f --- /dev/null +++ b/src/generators/app-lit-element-ts/templates/_my-app.test.ts @@ -0,0 +1,23 @@ +import { html, fixture, expect } from '@open-wc/testing'; + +import {<%= className %>} from '../src/<%= className %>.js'; +import '../src/<%= tagName %>.js'; + +describe('<%= className %>', () => { + let element: <%= className %>; + beforeEach(async () => { + element = await fixture(html` + <<%= tagName %>>> + `); + }); + + it('renders a h1', () => { + const h1 = element.shadowRoot!.querySelector('h1')!; + expect(h1).to.exist; + expect(h1.textContent).to.equal('My app'); + }); + + it('passes the a11y audit', async () => { + await expect(element).shadowDom.to.be.accessible(); + }); +}); diff --git a/src/generators/app-lit-element-ts/templates/_my-app.ts b/src/generators/app-lit-element-ts/templates/_my-app.ts new file mode 100644 index 0000000..10fa94e --- /dev/null +++ b/src/generators/app-lit-element-ts/templates/_my-app.ts @@ -0,0 +1,3 @@ +import { <%= className %> } from './<%= className %>.js'; + +customElements.define('<%= tagName %>', <%= className %>); diff --git a/src/generators/app-lit-element-ts/templates/_open-wc-logo.ts b/src/generators/app-lit-element-ts/templates/_open-wc-logo.ts new file mode 100644 index 0000000..858bade --- /dev/null +++ b/src/generators/app-lit-element-ts/templates/_open-wc-logo.ts @@ -0,0 +1,33 @@ +import { html } from 'lit-html'; + +export const openWcLogo = html` + + + + + + + + + + + +`; diff --git a/src/generators/app-lit-element-ts/templates/_package.json b/src/generators/app-lit-element-ts/templates/_package.json new file mode 100644 index 0000000..af48483 --- /dev/null +++ b/src/generators/app-lit-element-ts/templates/_package.json @@ -0,0 +1,19 @@ +{ + "name": "<%= tagName %>", + "license": "MIT", + "scripts": { + "start": "concurrently --kill-others --names tsc,web-dev-server \"npm run tsc:watch\" \"web-dev-server --app-index index.html --node-resolve --open --watch\"", + "tsc:watch": "tsc --watch" + }, + "dependencies": { + "lit-html": "^1.0.0", + "lit-element": "^2.0.1" + }, + "devDependencies": { + "@types/node": "13.11.1", + "@web/dev-server": "^0.0.12", + "typescript": "~4.0.3", + "concurrently": "^5.1.0", + "tslib": "^1.11.0" + } +} diff --git a/src/generators/app-lit-element-ts/templates/_tsconfig.json b/src/generators/app-lit-element-ts/templates/_tsconfig.json new file mode 100644 index 0000000..8914c73 --- /dev/null +++ b/src/generators/app-lit-element-ts/templates/_tsconfig.json @@ -0,0 +1,19 @@ + { + "compilerOptions": { + "target": "es2018", + "module": "esnext", + "moduleResolution": "node", + "noEmitOnError": true, + "lib": ["es2017", "dom"], + "strict": true, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "experimentalDecorators": true, + "importHelpers": true, + "outDir": "out-tsc", + "sourceMap": true, + "inlineSources": true, + "rootDir": "./" + }, + "include": ["**/*.ts"] +} diff --git a/src/generators/app-lit-element-ts/templates/custom-elements.json b/src/generators/app-lit-element-ts/templates/custom-elements.json new file mode 100644 index 0000000..d75bce3 --- /dev/null +++ b/src/generators/app-lit-element-ts/templates/custom-elements.json @@ -0,0 +1,26 @@ +{ + "version": 2, + "tags": [ + { + "name": "<%= tagName %>", + "description": "An application with a title and an action counter", + "properties": [ + { + "name": "title", + "type": "String", + "description": "The title of your application", + "default": "Hey there" + }, + { + "name": "page", + "type": "String", + "description": "Which page to show", + "default": "main" + } + ], + "events": [], + "slots": [], + "cssProperties": [] + } + ] +} diff --git a/src/generators/app-lit-element-ts/templates/static-demoing/.storybook/main.js b/src/generators/app-lit-element-ts/templates/static-demoing/.storybook/main.js new file mode 100644 index 0000000..1a4258d --- /dev/null +++ b/src/generators/app-lit-element-ts/templates/static-demoing/.storybook/main.js @@ -0,0 +1,14 @@ +module.exports = { + stories: ['../**/stories/*.stories.{js,md,mdx}'], + addons: [ + 'storybook-prebuilt/addon-knobs/register.js', + 'storybook-prebuilt/addon-docs/register.js', + 'storybook-prebuilt/addon-viewport/register.js', + ], + esDevServer: { + // custom es-dev-server options + nodeResolve: true, + watch: true, + open: true + }, +}; diff --git a/src/generators/app-lit-element-ts/templates/static-demoing/.storybook/preview.js b/src/generators/app-lit-element-ts/templates/static-demoing/.storybook/preview.js new file mode 100644 index 0000000..2cc90bb --- /dev/null +++ b/src/generators/app-lit-element-ts/templates/static-demoing/.storybook/preview.js @@ -0,0 +1,17 @@ +import { addParameters, setCustomElements } from '@open-wc/demoing-storybook'; + +addParameters({ + docs: { + iframeHeight: '200px', + } +}); + +async function run() { + const customElements = await ( + await fetch(new URL('../custom-elements.json', import.meta.url)) + ).json(); + + setCustomElements(customElements); +} + +run(); diff --git a/src/generators/app-lit-element-ts/templates/static-testing/web-test-runner.config.mjs b/src/generators/app-lit-element-ts/templates/static-testing/web-test-runner.config.mjs new file mode 100644 index 0000000..e22a691 --- /dev/null +++ b/src/generators/app-lit-element-ts/templates/static-testing/web-test-runner.config.mjs @@ -0,0 +1,4 @@ +export default { + files: 'out-tsc/test/**/*.test.js', + nodeResolve: true +}; \ No newline at end of file diff --git a/src/generators/app-lit-element-ts/templates/static/README.md b/src/generators/app-lit-element-ts/templates/static/README.md new file mode 100644 index 0000000..df8ad47 --- /dev/null +++ b/src/generators/app-lit-element-ts/templates/static/README.md @@ -0,0 +1,30 @@ +

+ +

+ +## Open-wc Starter App + +[![Built with open-wc recommendations](https://img.shields.io/badge/built%20with-open--wc-blue.svg)](https://github.com/open-wc) + +## Quickstart + +To get started: + +```sh +npm init @open-wc +# requires node 10 & npm 6 or higher +``` + +## Scripts + +- `start` runs your app for development, reloading on file changes +- `start:build` runs your app after it has been built using the build command +- `build` builds your app and outputs it in your `dist` directory +- `test` runs your test suite with Web Test Runner +- `lint` runs the linter for your project + +## Tooling configs + +For most of the tools, the configuration is in the `package.json` to reduce the amount of files in your project. + +If you customize the configuration a lot, you can consider moving them to individual files. \ No newline at end of file diff --git a/src/generators/app-lit-element-ts/templates/static/index.html b/src/generators/app-lit-element-ts/templates/static/index.html new file mode 100644 index 0000000..b5be0d1 --- /dev/null +++ b/src/generators/app-lit-element-ts/templates/static/index.html @@ -0,0 +1,28 @@ + + + + + + + + + + + <%= tagName %> + + + + <<%= tagName %>>> + + + + + \ No newline at end of file diff --git a/src/generators/app-lit-element/index.js b/src/generators/app-lit-element/index.js new file mode 100644 index 0000000..bf0e13a --- /dev/null +++ b/src/generators/app-lit-element/index.js @@ -0,0 +1,76 @@ +import { CommonRepoMixin } from '../common-repo/index.js'; + +/* eslint-disable no-console */ +export const AppLitElementMixin = subclass => + class extends CommonRepoMixin(subclass) { + async execute() { + await super.execute(); + + const { tagName, className } = this.templateData; + + // write & rename el class template + this.copyTemplate( + `${__dirname}/templates/_my-app.js`, + this.destinationPath(`src//${tagName}.js`), + ); + + this.copyTemplate( + `${__dirname}/templates/_MyApp.js`, + this.destinationPath(`src/${className}.js`), + ); + + this.copyTemplate( + `${__dirname}/templates/_open-wc-logo.js`, + this.destinationPath(`src/open-wc-logo.js`), + ); + + this.copyTemplateJsonInto( + `${__dirname}/templates/_package.json`, + this.destinationPath('package.json'), + ); + + await this.copyTemplates(`${__dirname}/templates/static/**/*`); + + this.copyTemplate( + `${__dirname}/templates/custom-elements.json`, + this.destinationPath('custom-elements.json'), + ); + + if (this.options.features && this.options.features.includes('testing')) { + await this.copyTemplates(`${__dirname}/templates/static-testing/**/*`); + } + + if (this.options.features && this.options.features.includes('demoing')) { + await this.copyTemplates(`${__dirname}/templates/static-demoing/**/*`); + } + + if (this.options.scaffoldFilesFor && this.options.scaffoldFilesFor.includes('demoing')) { + this.copyTemplate( + `${__dirname}/templates/_my-app.stories.js`, + this.destinationPath(`./stories/${tagName}.stories.js`), + ); + + await this.copyTemplates(`${__dirname}/templates/static-scaffold-demoing/**/*`); + } + + if (this.options.scaffoldFilesFor && this.options.scaffoldFilesFor.includes('testing')) { + this.copyTemplate( + `${__dirname}/templates/_my-app.test.js`, + this.destinationPath(`./test/${tagName}.test.js`), + ); + + await this.copyTemplates(`${__dirname}/templates/static-scaffold-testing/**/*`); + } + } + + async end() { + await super.end(); + console.log(''); + console.log('You are all set up now!'); + console.log(''); + console.log('All you need to do is run:'); + console.log(` cd ${this.templateData.tagName}`); + console.log(' npm run start'); + console.log(''); + } + }; diff --git a/src/generators/app-lit-element/templates/_MyApp.js b/src/generators/app-lit-element/templates/_MyApp.js new file mode 100644 index 0000000..e15a313 --- /dev/null +++ b/src/generators/app-lit-element/templates/_MyApp.js @@ -0,0 +1,84 @@ +import { LitElement, html, css } from 'lit-element'; +import { openWcLogo } from './open-wc-logo.js'; + +export class <%= className %> extends LitElement { + static get properties() { + return { + title: { type: String }, + page: { type: String }, + }; + } + + static get styles() { + return css` + :host { + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + font-size: calc(10px + 2vmin); + color: #1a2b42; + max-width: 960px; + margin: 0 auto; + text-align: center; + } + + main { + flex-grow: 1; + } + + .logo > svg { + margin-top: 36px; + animation: app-logo-spin infinite 20s linear; + } + + @keyframes app-logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } + } + + .app-footer { + font-size: calc(12px + 0.5vmin); + align-items: center; + } + + .app-footer a { + margin-left: 5px; + } + `; + } + + render() { + return html` +
+ +

My app

+ +

Edit src/<%= className %>.js and save to reload.

+ + Code examples + +
+ + + `; + } +} diff --git a/src/generators/app-lit-element/templates/_my-app.js b/src/generators/app-lit-element/templates/_my-app.js new file mode 100644 index 0000000..10fa94e --- /dev/null +++ b/src/generators/app-lit-element/templates/_my-app.js @@ -0,0 +1,3 @@ +import { <%= className %> } from './<%= className %>.js'; + +customElements.define('<%= tagName %>', <%= className %>); diff --git a/src/generators/app-lit-element/templates/_my-app.stories.js b/src/generators/app-lit-element/templates/_my-app.stories.js new file mode 100644 index 0000000..ef6b3ab --- /dev/null +++ b/src/generators/app-lit-element/templates/_my-app.stories.js @@ -0,0 +1,11 @@ +import { html } from 'lit-html'; +import '../src/<%= tagName %>.js'; + +export default { + title: '<%= tagName %>', +}; + +export const App = () => + html` + <<%= tagName %>>> + `; diff --git a/src/generators/app-lit-element/templates/_my-app.test.js b/src/generators/app-lit-element/templates/_my-app.test.js new file mode 100644 index 0000000..bd1b1d1 --- /dev/null +++ b/src/generators/app-lit-element/templates/_my-app.test.js @@ -0,0 +1,22 @@ +import { html, fixture, expect } from '@open-wc/testing'; + +import '../src/<%= tagName %>.js'; + +describe('<%= className %>', () => { + let element; + beforeEach(async () => { + element = await fixture(html` + <<%= tagName %>>> + `); + }); + + it('renders a h1', () => { + const h1 = element.shadowRoot.querySelector('h1'); + expect(h1).to.exist; + expect(h1.textContent).to.equal('My app'); + }); + + it('passes the a11y audit', async () => { + await expect(element).shadowDom.to.be.accessible(); + }); +}); diff --git a/src/generators/app-lit-element/templates/_open-wc-logo.js b/src/generators/app-lit-element/templates/_open-wc-logo.js new file mode 100644 index 0000000..858bade --- /dev/null +++ b/src/generators/app-lit-element/templates/_open-wc-logo.js @@ -0,0 +1,33 @@ +import { html } from 'lit-html'; + +export const openWcLogo = html` + + + + + + + + + + + +`; diff --git a/src/generators/app-lit-element/templates/_package.json b/src/generators/app-lit-element/templates/_package.json new file mode 100644 index 0000000..d2d49d1 --- /dev/null +++ b/src/generators/app-lit-element/templates/_package.json @@ -0,0 +1,14 @@ +{ + "name": "<%= tagName %>", + "license": "MIT", + "scripts": { + "start": "web-dev-server --app-index index.html --node-resolve --open --watch" + }, + "dependencies": { + "lit-html": "^1.0.0", + "lit-element": "^2.0.1" + }, + "devDependencies": { + "@web/dev-server": "^0.0.12" + } +} \ No newline at end of file diff --git a/src/generators/app-lit-element/templates/custom-elements.json b/src/generators/app-lit-element/templates/custom-elements.json new file mode 100644 index 0000000..d75bce3 --- /dev/null +++ b/src/generators/app-lit-element/templates/custom-elements.json @@ -0,0 +1,26 @@ +{ + "version": 2, + "tags": [ + { + "name": "<%= tagName %>", + "description": "An application with a title and an action counter", + "properties": [ + { + "name": "title", + "type": "String", + "description": "The title of your application", + "default": "Hey there" + }, + { + "name": "page", + "type": "String", + "description": "Which page to show", + "default": "main" + } + ], + "events": [], + "slots": [], + "cssProperties": [] + } + ] +} diff --git a/src/generators/app-lit-element/templates/static-demoing/.storybook/main.js b/src/generators/app-lit-element/templates/static-demoing/.storybook/main.js new file mode 100644 index 0000000..1a4258d --- /dev/null +++ b/src/generators/app-lit-element/templates/static-demoing/.storybook/main.js @@ -0,0 +1,14 @@ +module.exports = { + stories: ['../**/stories/*.stories.{js,md,mdx}'], + addons: [ + 'storybook-prebuilt/addon-knobs/register.js', + 'storybook-prebuilt/addon-docs/register.js', + 'storybook-prebuilt/addon-viewport/register.js', + ], + esDevServer: { + // custom es-dev-server options + nodeResolve: true, + watch: true, + open: true + }, +}; diff --git a/src/generators/app-lit-element/templates/static-demoing/.storybook/preview.js b/src/generators/app-lit-element/templates/static-demoing/.storybook/preview.js new file mode 100644 index 0000000..2cc90bb --- /dev/null +++ b/src/generators/app-lit-element/templates/static-demoing/.storybook/preview.js @@ -0,0 +1,17 @@ +import { addParameters, setCustomElements } from '@open-wc/demoing-storybook'; + +addParameters({ + docs: { + iframeHeight: '200px', + } +}); + +async function run() { + const customElements = await ( + await fetch(new URL('../custom-elements.json', import.meta.url)) + ).json(); + + setCustomElements(customElements); +} + +run(); diff --git a/src/generators/app-lit-element/templates/static-testing/web-test-runner.config.mjs b/src/generators/app-lit-element/templates/static-testing/web-test-runner.config.mjs new file mode 100644 index 0000000..bbb5f73 --- /dev/null +++ b/src/generators/app-lit-element/templates/static-testing/web-test-runner.config.mjs @@ -0,0 +1,4 @@ +export default { + files: 'test/**/*.test.js', + nodeResolve: true +}; \ No newline at end of file diff --git a/src/generators/app-lit-element/templates/static/README.md b/src/generators/app-lit-element/templates/static/README.md new file mode 100644 index 0000000..32da54f --- /dev/null +++ b/src/generators/app-lit-element/templates/static/README.md @@ -0,0 +1,30 @@ +

+ +

+ +## Open-wc Starter App + +[![Built with open-wc recommendations](https://img.shields.io/badge/built%20with-open--wc-blue.svg)](https://github.com/open-wc) + +## Quickstart + +To get started: + +```bash +npm init @open-wc +# requires node 10 & npm 6 or higher +``` + +## Scripts + +- `start` runs your app for development, reloading on file changes +- `start:build` runs your app after it has been built using the build command +- `build` builds your app and outputs it in your `dist` directory +- `test` runs your test suite with Web Test Runner +- `lint` runs the linter for your project + +## Tooling configs + +For most of the tools, the configuration is in the `package.json` to reduce the amount of files in your project. + +If you customize the configuration a lot, you can consider moving them to individual files. \ No newline at end of file diff --git a/src/generators/app-lit-element/templates/static/index.html b/src/generators/app-lit-element/templates/static/index.html new file mode 100644 index 0000000..c1e02c5 --- /dev/null +++ b/src/generators/app-lit-element/templates/static/index.html @@ -0,0 +1,28 @@ + + + + + + + + + + + <%= tagName %> + + + + <<%= tagName %>>> + + + + + \ No newline at end of file diff --git a/src/generators/app/executeViaOptions.js b/src/generators/app/executeViaOptions.js new file mode 100644 index 0000000..d2376f4 --- /dev/null +++ b/src/generators/app/executeViaOptions.js @@ -0,0 +1,8 @@ +import { executeMixinGenerator } from '../../core.js'; +import { gatherMixins } from './gatherMixins.js'; + +export async function executeViaOptions(options) { + const mixins = gatherMixins(options); + + await executeMixinGenerator(mixins, options); +} diff --git a/src/generators/app/gatherMixins.js b/src/generators/app/gatherMixins.js new file mode 100644 index 0000000..21e762c --- /dev/null +++ b/src/generators/app/gatherMixins.js @@ -0,0 +1,112 @@ +import { WcLitElementMixin, WcLitElementPackageMixin } from '../wc-lit-element/index.js'; +import { LintingMixin } from '../linting/index.js'; +import { TestingMixin, TestingScaffoldMixin } from '../testing/index.js'; +import { + DemoingStorybookMixin, + DemoingStorybookScaffoldMixin, +} from '../demoing-storybook/index.js'; +import { BuildingRollupMixin } from '../building-rollup/index.js'; +// ts +import { TsWcLitElementMixin, TsWcLitElementPackageMixin } from '../wc-lit-element-ts/index.js'; +import { TsLintingMixin } from '../linting-ts/index.js'; +import { TsTestingMixin, TsTestingScaffoldMixin } from '../testing-ts/index.js'; +import { + TsDemoingStorybookMixin, + TsDemoingStorybookScaffoldMixin, +} from '../demoing-storybook-ts/index.js'; +import { TsBuildingRollupMixin } from '../building-rollup-ts/index.js'; + +export function gatherMixins(options) { + let considerScaffoldFilesFor = false; + const mixins = []; + + if (options.type === 'scaffold') { + if (options.typescript === 'true') { + switch (options.scaffoldType) { + case 'wc': + mixins.push(TsWcLitElementPackageMixin); + considerScaffoldFilesFor = true; + break; + case 'wc-lit-element': + mixins.push(TsWcLitElementMixin); + considerScaffoldFilesFor = true; + break; + // no default + } + } else { + switch (options.scaffoldType) { + case 'wc': + mixins.push(WcLitElementPackageMixin); + considerScaffoldFilesFor = true; + break; + case 'wc-lit-element': + mixins.push(WcLitElementMixin); + considerScaffoldFilesFor = true; + break; + // no default + } + } + } + + if (options.features && options.features.length > 0) { + if (options.typescript === 'true') { + options.features.forEach(feature => { + if (feature === 'linting') { + mixins.push(TsLintingMixin); + } + if (feature === 'testing') { + mixins.push(TsTestingMixin); + } + if (feature === 'demoing') { + mixins.push(TsDemoingStorybookMixin); + } + if (feature === 'building') { + mixins.push(TsBuildingRollupMixin); + } + }); + } else { + options.features.forEach(feature => { + if (feature === 'linting') { + mixins.push(LintingMixin); + } + if (feature === 'testing') { + mixins.push(TestingMixin); + } + if (feature === 'demoing') { + mixins.push(DemoingStorybookMixin); + } + if (feature === 'building') { + mixins.push(BuildingRollupMixin); + } + }); + } + } + + if (considerScaffoldFilesFor && options.scaffoldFilesFor && options.scaffoldFilesFor.length > 0) { + options.scaffoldFilesFor.forEach(feature => { + if (options.typescript === 'true') { + switch (feature) { + case 'testing': + mixins.push(TsTestingScaffoldMixin); + break; + case 'demoing': + mixins.push(TsDemoingStorybookScaffoldMixin); + break; + // no default + } + } else { + switch (feature) { + case 'testing': + mixins.push(TestingScaffoldMixin); + break; + case 'demoing': + mixins.push(DemoingStorybookScaffoldMixin); + break; + // no default + } + } + }); + } + + return mixins; +} diff --git a/src/generators/app/header.js b/src/generators/app/header.js new file mode 100644 index 0000000..468f908 --- /dev/null +++ b/src/generators/app/header.js @@ -0,0 +1,16 @@ +import chalk from 'chalk'; + +export default ` + _.,,,,,,,,,._ + .d'' \`\`b. ${chalk.underline('Open Web Components Recommendations')} + .p' Open \`q. + .d' Web Components \`b. Start or upgrade your web component project with + .d' \`b. ease. All our recommendations at your fingertips. + :: ................. :: + \`p. .q' See more details at https://open-wc.org/init/ + \`p. open-wc.org .q' + \`b. @openWc .d' + \`q.. ..,' Note: you can exit any time with Ctrl+C or Esc + '',,,,,,,,,,'' + +`; diff --git a/src/generators/app/index.js b/src/generators/app/index.js new file mode 100644 index 0000000..978574f --- /dev/null +++ b/src/generators/app/index.js @@ -0,0 +1,147 @@ +/* eslint-disable no-console */ +import prompts from 'prompts'; +import commandLineArgs from 'command-line-args'; +import { executeMixinGenerator } from '../../core.js'; +import { AppLitElementMixin } from '../app-lit-element/index.js'; +import { TsAppLitElementMixin } from '../app-lit-element-ts/index.js'; + +import header from './header.js'; +import { gatherMixins } from './gatherMixins.js'; + +/** + * Allows to control the data via command line + * + * example: + * npm init @open-wc --type scaffold --scaffoldType app --tagName foo-bar --installDependencies false + * npm init @open-wc --type upgrade --features linting demoing --tagName foo-bar --scaffoldFilesFor demoing --installDependencies false + */ +const optionDefinitions = [ + { name: 'destinationPath', type: String }, // path + { name: 'type', type: String }, // scaffold, upgrade + { name: 'scaffoldType', type: String }, // wc, app + { name: 'features', type: String, multiple: true }, // linting, testing, demoing, building + { name: 'scaffoldFilesFor', type: String, multiple: true }, // testing, demoing, building + { name: 'typescript', type: String }, + { name: 'tagName', type: String }, + { name: 'installDependencies', type: String }, // yarn, npm, false + { name: 'writeToDisk', type: String }, // true, false +]; +const overrides = commandLineArgs(optionDefinitions); +prompts.override(overrides); + +export const AppMixin = subclass => + // eslint-disable-next-line no-shadow + class AppMixin extends subclass { + constructor() { + super(); + this.wantsNpmInstall = false; + this.wantsWriteToDisk = false; + this.wantsRecreateInfo = false; + } + + async execute() { + console.log(header); + const scaffoldOptions = []; + const questions = [ + { + type: 'select', + name: 'type', + message: 'What would you like to do today?', + choices: [ + { title: 'Scaffold a new project', value: 'scaffold' }, + { title: 'Upgrade an existing project', value: 'upgrade' }, + ], + }, + { + type: (prev, all) => (all.type === 'scaffold' ? 'select' : null), + name: 'scaffoldType', + message: 'What would you like to scaffold?', + choices: [ + { title: 'Web Component', value: 'wc' }, + { title: 'Application', value: 'app' }, + ], + }, + { + type: (prev, all) => + all.scaffoldType === 'wc' || all.scaffoldType === 'app' || all.type === 'upgrade' + ? 'multiselect' + : null, + name: 'features', + message: 'What would you like to add?', + choices: (prev, all) => + [ + { title: 'Linting (eslint & prettier)', value: 'linting' }, + { title: 'Testing (web-test-runner)', value: 'testing' }, + { title: 'Demoing (storybook)', value: 'demoing' }, + all.scaffoldType !== 'wc' && { + title: 'Building (rollup)', + value: 'building', + }, + ].filter(_ => !!_), + onState: state => { + state.value.forEach(meta => { + if (meta.selected === true && meta.value !== 'linting') { + scaffoldOptions.push({ + title: meta.title, + value: meta.value, + }); + } + }); + }, + }, + { + type: 'select', + name: 'typescript', + message: 'Would you like to use typescript?', + choices: [ + { title: 'No', value: 'false' }, + { title: 'Yes', value: 'true' }, + ], + }, + { + type: () => (scaffoldOptions.length > 0 ? 'multiselect' : null), + name: 'scaffoldFilesFor', + message: 'Would you like to scaffold examples files for?', + choices: scaffoldOptions, + }, + { + type: 'text', + name: 'tagName', + message: 'What is the tag name of your application/web component?', + validate: tagName => + !/^([a-z])(?!.*[<>])(?=.*-).+$/.test(tagName) + ? 'You need a minimum of two words separated by dashes (e.g. foo-bar)' + : true, + }, + ]; + + /** + * { + * type: 'scaffold', + * scaffoldType: 'wc', + * features: [ 'testing', 'building' ], + * scaffoldFilesFor: [ 'testing' ], + * tagName: 'foo-bar', + * installDependencies: 'false' + * } + */ + this.options = await prompts(questions, { + onCancel: () => { + process.exit(); + }, + }); + + const mixins = gatherMixins(this.options); + // app is separate to prevent circular imports + if (this.options.type === 'scaffold' && this.options.scaffoldType === 'app') { + if (this.options.typescript === 'true') { + mixins.push(TsAppLitElementMixin); + } else { + mixins.push(AppLitElementMixin); + } + } + await executeMixinGenerator(mixins, this.options); + } + }; + +export default AppMixin; diff --git a/src/generators/building-rollup-ts/index.js b/src/generators/building-rollup-ts/index.js new file mode 100644 index 0000000..629fe6c --- /dev/null +++ b/src/generators/building-rollup-ts/index.js @@ -0,0 +1,13 @@ +export const TsBuildingRollupMixin = subclass => + class extends subclass { + async execute() { + await super.execute(); + + this.copyTemplateJsonInto( + `${__dirname}/templates/_package.json`, + this.destinationPath('package.json'), + ); + + await this.copyTemplates(`${__dirname}/templates/static/**/*`); + } + }; diff --git a/src/generators/building-rollup-ts/templates/_package.json b/src/generators/building-rollup-ts/templates/_package.json new file mode 100644 index 0000000..52ff241 --- /dev/null +++ b/src/generators/building-rollup-ts/templates/_package.json @@ -0,0 +1,12 @@ +{ + "scripts": { + "build": "rimraf dist && tsc && rollup -c rollup.config.js", + "start:build": "npm run build && web-dev-server --root-dir dist --app-index index.html --open --compatibility none" + }, + "devDependencies": { + "@open-wc/building-rollup": "^1.0.0", + "deepmerge": "^4.2.2", + "rimraf": "^2.6.3", + "rollup": "^2.3.4" + } +} \ No newline at end of file diff --git a/src/generators/building-rollup-ts/templates/static/rollup.config.js b/src/generators/building-rollup-ts/templates/static/rollup.config.js new file mode 100644 index 0000000..babc0bf --- /dev/null +++ b/src/generators/building-rollup-ts/templates/static/rollup.config.js @@ -0,0 +1,31 @@ +import merge from 'deepmerge'; +// use createSpaConfig for bundling a Single Page App +import { createSpaConfig } from '@open-wc/building-rollup'; + +// use createBasicConfig to do regular JS to JS bundling +// import { createBasicConfig } from '@open-wc/building-rollup'; + +const baseConfig = createSpaConfig({ + // use the outputdir option to modify where files are output + // outputDir: 'dist', + + // if you need to support older browsers, such as IE11, set the legacyBuild + // option to generate an additional build just for this browser + // legacyBuild: true, + + // development mode creates a non-minified build for debugging or development + developmentMode: process.env.ROLLUP_WATCH === 'true', + + // set to true to inject the service worker registration into your index.html + injectServiceWorker: false, +}); + +export default merge(baseConfig, { + // if you use createSpaConfig, you can use your index.html as entrypoint, + // any + +<<%= tagName %>>> +``` + +<%= featureReadmes %> + +## Tooling configs + +For most of the tools, the configuration is in the `package.json` to reduce the amount of files in your project. + +If you customize the configuration a lot, you can consider moving them to individual files. + +## Local Demo with `web-dev-server` +```bash +npm start +``` +To run a local development server that serves the basic demo located in `demo/index.html` diff --git a/src/generators/wc-lit-element-ts/templates/static/demo/index.html b/src/generators/wc-lit-element-ts/templates/static/demo/index.html new file mode 100644 index 0000000..cd85c2b --- /dev/null +++ b/src/generators/wc-lit-element-ts/templates/static/demo/index.html @@ -0,0 +1,29 @@ + + + + + + + +
+ + + + diff --git a/src/generators/wc-lit-element-ts/templates/static/index.ts b/src/generators/wc-lit-element-ts/templates/static/index.ts new file mode 100644 index 0000000..a25793a --- /dev/null +++ b/src/generators/wc-lit-element-ts/templates/static/index.ts @@ -0,0 +1 @@ +export { <%= className %> } from './src/<%= className %>.js'; diff --git a/src/generators/wc-lit-element/index.js b/src/generators/wc-lit-element/index.js new file mode 100644 index 0000000..bc4e5ee --- /dev/null +++ b/src/generators/wc-lit-element/index.js @@ -0,0 +1,71 @@ +/* eslint-disable max-classes-per-file */ +import { join } from 'path'; +import { CommonRepoMixin } from '../common-repo/index.js'; +import { processTemplate, readFileFromPath } from '../../core.js'; + +const compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args))); +const safeReduce = (f, initial) => xs => (Array.isArray(xs) ? xs.reduce(f, initial) : xs); + +const getTemplatePart = compose(processTemplate, readFileFromPath); + +function featureReadmeBlurb(feature) { + const path = join(__dirname, `./templates/partials/README.${feature}.md`); + return getTemplatePart(path); +} + +function featureReadme(acc, feature, i, a) { + return `${acc + featureReadmeBlurb(feature)}${i === a.length - 1 ? '' : '\n'}`; +} + +const safeFeatureReadme = safeReduce(featureReadme, ''); + +/* eslint-disable no-console */ +export const WcLitElementMixin = subclass => + class extends subclass { + async execute() { + this.templateData.featureReadmes = safeFeatureReadme(this.options.features); + this.templateData.scriptRunCommand = + this.options.installDependencies === 'yarn' ? 'yarn' : 'npm run'; + + await super.execute(); + const { tagName, className } = this.templateData; + + // write & rename el class template + this.copyTemplate( + `${__dirname}/templates/_MyEl.js`, + this.destinationPath(`src/${className}.js`), + ); + + // write & rename el registration template + this.copyTemplate(`${__dirname}/templates/_my-el.js`, this.destinationPath(`${tagName}.js`)); + + await this.copyTemplates(`${__dirname}/templates/static/**/*`); + } + }; + +export const WcLitElementPackageMixin = subclass => + class extends CommonRepoMixin(WcLitElementMixin(subclass)) { + async execute() { + await super.execute(); + // write & rename package.json + this.copyTemplateJsonInto( + `${__dirname}/templates/_package.json`, + this.destinationPath('package.json'), + ); + this.copyTemplate( + `${__dirname}/templates/custom-elements.json`, + this.destinationPath('custom-elements.json'), + ); + } + + async end() { + await super.end(); + console.log(''); + console.log('You are all set up now!'); + console.log(''); + console.log('All you need to do is run:'); + console.log(` cd ${this.templateData.tagName}`); + console.log(' npm run start'); + console.log(''); + } + }; diff --git a/src/generators/wc-lit-element/templates/_MyEl.js b/src/generators/wc-lit-element/templates/_MyEl.js new file mode 100644 index 0000000..baec5b9 --- /dev/null +++ b/src/generators/wc-lit-element/templates/_MyEl.js @@ -0,0 +1,37 @@ +import { html, css, LitElement } from 'lit-element'; + +export class <%= className %> extends LitElement { + static get styles() { + return css` + :host { + display: block; + padding: 25px; + color: var(--<%= tagName %>-text-color, #000); + } + `; + } + + static get properties() { + return { + title: { type: String }, + counter: { type: Number }, + }; + } + + constructor() { + super(); + this.title = 'Hey there'; + this.counter = 5; + } + + __increment() { + this.counter += 1; + } + + render() { + return html` +

${this.title} Nr. ${this.counter}!

+ + `; + } +} diff --git a/src/generators/wc-lit-element/templates/_my-el.js b/src/generators/wc-lit-element/templates/_my-el.js new file mode 100644 index 0000000..4a58505 --- /dev/null +++ b/src/generators/wc-lit-element/templates/_my-el.js @@ -0,0 +1,3 @@ +import { <%= className %> } from './src/<%= className %>.js'; + +window.customElements.define('<%= tagName %>', <%= className %>); diff --git a/src/generators/wc-lit-element/templates/_package.json b/src/generators/wc-lit-element/templates/_package.json new file mode 100644 index 0000000..ec2c3a6 --- /dev/null +++ b/src/generators/wc-lit-element/templates/_package.json @@ -0,0 +1,14 @@ +{ + "main": "index.js", + "module": "index.js", + "scripts": { + "start": "web-dev-server --app-index demo/index.html --node-resolve --open --watch" + }, + "dependencies": { + "lit-html": "^1.1.2", + "lit-element": "^2.2.1" + }, + "devDependencies": { + "@web/dev-server": "^0.0.12" + } +} \ No newline at end of file diff --git a/src/generators/wc-lit-element/templates/custom-elements.json b/src/generators/wc-lit-element/templates/custom-elements.json new file mode 100644 index 0000000..2453885 --- /dev/null +++ b/src/generators/wc-lit-element/templates/custom-elements.json @@ -0,0 +1,32 @@ +{ + "version": 2, + "tags": [ + { + "name": "<%= tagName %>", + "description": "A component with a title and an action counter", + "properties": [ + { + "name": "title", + "type": "String", + "description": "The title of your component", + "default": "Hey there" + }, + { + "name": "counter", + "type": "Number", + "description": "An action counter", + "default": 0 + } + ], + "events": [], + "slots": [], + "cssProperties": [ + { + "name": "--<%= tagName %>-text-color", + "description": "Main Text Color", + "type": "Color" + } + ] + } + ] +} diff --git a/src/generators/wc-lit-element/templates/partials/README.demoing.md b/src/generators/wc-lit-element/templates/partials/README.demoing.md new file mode 100644 index 0000000..b34f4d4 --- /dev/null +++ b/src/generators/wc-lit-element/templates/partials/README.demoing.md @@ -0,0 +1,10 @@ +## Demoing with Storybook +To run a local instance of Storybook for your component, run +```bash +<%= scriptRunCommand %> storybook +``` + +To build a production version of Storybook, run +```bash +<%= scriptRunCommand %> storybook:build +``` diff --git a/src/generators/wc-lit-element/templates/partials/README.linting.md b/src/generators/wc-lit-element/templates/partials/README.linting.md new file mode 100644 index 0000000..6d232c3 --- /dev/null +++ b/src/generators/wc-lit-element/templates/partials/README.linting.md @@ -0,0 +1,26 @@ +## Linting with ESLint, Prettier, and Types +To scan the project for linting errors, run +```bash +<%= scriptRunCommand %> lint +``` + +You can lint with ESLint and Prettier individually as well +```bash +<%= scriptRunCommand %> lint:eslint +``` +```bash +<%= scriptRunCommand %> lint:prettier +``` + +To automatically fix many linting errors, run +```bash +<%= scriptRunCommand %> format +``` + +You can format using ESLint and Prettier individually as well +```bash +<%= scriptRunCommand %> format:eslint +``` +```bash +<%= scriptRunCommand %> format:prettier +``` diff --git a/src/generators/wc-lit-element/templates/partials/README.testing.md b/src/generators/wc-lit-element/templates/partials/README.testing.md new file mode 100644 index 0000000..e4ef68a --- /dev/null +++ b/src/generators/wc-lit-element/templates/partials/README.testing.md @@ -0,0 +1,11 @@ +## Testing with Web Test Runner +To run the suite of Web Test Runner tests, run +```bash +<%= scriptRunCommand %> test +``` + +To run the tests in watch mode (for TDD, for example), run + +```bash +<%= scriptRunCommand %> test:watch +``` diff --git a/src/generators/wc-lit-element/templates/static/README.md b/src/generators/wc-lit-element/templates/static/README.md new file mode 100644 index 0000000..f59bf97 --- /dev/null +++ b/src/generators/wc-lit-element/templates/static/README.md @@ -0,0 +1,31 @@ +# \<<%= tagName %>> + +This webcomponent follows the [open-wc](https://github.com/open-wc/open-wc) recommendation. + +## Installation +```bash +npm i <%= tagName %> +``` + +## Usage +```html + + +<<%= tagName %>>> +``` + +<%= featureReadmes %> + +## Tooling configs + +For most of the tools, the configuration is in the `package.json` to reduce the amount of files in your project. + +If you customize the configuration a lot, you can consider moving them to individual files. + +## Local Demo with `web-dev-server` +```bash +npm start +``` +To run a local development server that serves the basic demo located in `demo/index.html` diff --git a/src/generators/wc-lit-element/templates/static/demo/index.html b/src/generators/wc-lit-element/templates/static/demo/index.html new file mode 100644 index 0000000..a540bb6 --- /dev/null +++ b/src/generators/wc-lit-element/templates/static/demo/index.html @@ -0,0 +1,29 @@ + + + + + + + +
+ + + + diff --git a/src/generators/wc-lit-element/templates/static/index.js b/src/generators/wc-lit-element/templates/static/index.js new file mode 100644 index 0000000..a25793a --- /dev/null +++ b/src/generators/wc-lit-element/templates/static/index.js @@ -0,0 +1 @@ +export { <%= className %> } from './src/<%= className %>.js'; diff --git a/test/core.test.js b/test/core.test.js new file mode 100644 index 0000000..5f05c18 --- /dev/null +++ b/test/core.test.js @@ -0,0 +1,393 @@ +/* eslint-disable no-template-curly-in-string */ + +import chai from 'chai'; +import fs from 'fs'; +import { + copyTemplateJsonInto, + copyTemplates, + deleteVirtualFile, + executeMixinGenerator, + filesToTree, + optionsToCommand, + processTemplate, + readFileFromPath, + resetVirtualFiles, + setOverrideAllFiles, + virtualFiles, + writeFileToPath, + writeFileToPathOnDisk, +} from '../src/core.js'; + +const { expect } = chai; + +describe('processTemplate', () => { + it('replaces <%= keyName %> in source if provided as data', async () => { + expect(processTemplate('prefix <%= name %> suffix', { name: 'foo' })).to.equal( + 'prefix foo suffix', + ); + }); + + it('replaces multiple instances <%= keyName %> in source if provided as data', async () => { + expect(processTemplate('prefix <%= name %> suffix <%= name %>', { name: 'foo' })).to.equal( + 'prefix foo suffix foo', + ); + }); + + it('ignores <%= keyName %> in source if not provided as data', async () => { + expect(processTemplate('prefix <%= name %> suffix', { foo: 'foo' })).to.equal( + 'prefix <%= name %> suffix', + ); + }); +}); + +describe('writeFileToPath', () => { + beforeEach(() => { + resetVirtualFiles(); + }); + + it('stores file to write in an array', async () => { + writeFileToPath('foo/bar.js', 'barfile'); + expect(virtualFiles).to.deep.equal([{ path: 'foo/bar.js', content: 'barfile' }]); + writeFileToPath('foo/baz.js', 'bazfile'); + expect(virtualFiles).to.deep.equal([ + { path: 'foo/bar.js', content: 'barfile' }, + { path: 'foo/baz.js', content: 'bazfile' }, + ]); + }); + + it('will override content for the same path', async () => { + writeFileToPath('foo/bar.js', 'barfile'); + writeFileToPath('foo/bar.js', 'updated barfile'); + expect(virtualFiles).to.deep.equal([{ path: 'foo/bar.js', content: 'updated barfile' }]); + }); +}); + +describe('readFileFromPath', () => { + beforeEach(() => { + resetVirtualFiles(); + fs.writeFileSync(`./__tmpfoo.txt`, 'content of foo'); + }); + afterEach(() => { + if (fs.existsSync(`./__tmpfoo.txt`)) { + fs.unlinkSync(`./__tmpfoo.txt`); + } + }); + + it('return false for non existing files', async () => { + expect(readFileFromPath('non/existing/path.txt')).to.be.false; + }); + + it('reads file from disk', async () => { + expect(readFileFromPath(`./__tmpfoo.txt`)).to.equal('content of foo'); + }); + + it('reads file from virtual then from disk', async () => { + writeFileToPath(`./__tmpfoo.txt`, 'virtual foo'); + expect(readFileFromPath(`./__tmpfoo.txt`)).to.equal('virtual foo'); + }); +}); + +describe('deleteVirtualFile', () => { + beforeEach(() => { + resetVirtualFiles(); + }); + + it('removes an entry from the array of virtual files', async () => { + writeFileToPath('foo/bar.js', 'barfile'); + expect(virtualFiles).to.deep.equal([{ path: 'foo/bar.js', content: 'barfile' }]); + + deleteVirtualFile('foo/bar.js'); + expect(virtualFiles).to.deep.equal([]); + }); +}); + +describe('writeFileToPathOnDisk', () => { + beforeEach(() => { + fs.writeFileSync(`./__tmpfoo.txt`, 'content of foo'); + }); + afterEach(() => { + if (fs.existsSync(`./__tmpfoo.txt`)) { + fs.unlinkSync(`./__tmpfoo.txt`); + } + }); + + it('will not override by default', async () => { + await writeFileToPathOnDisk(`./__tmpfoo.txt`, 'updatedfoofile', { ask: false }); + expect(fs.readFileSync(`./__tmpfoo.txt`, 'utf-8')).to.equal('content of foo'); + }); + + it('will override if set', async () => { + await writeFileToPathOnDisk(`./__tmpfoo.txt`, 'updatedfoofile', { + override: true, + ask: false, + }); + expect(fs.readFileSync(`./__tmpfoo.txt`, 'utf-8')).to.equal('updatedfoofile'); + }); + + it('will override if setOverrideAllFiles(true) is used', async () => { + setOverrideAllFiles(true); + await writeFileToPathOnDisk(`./__tmpfoo.txt`, 'updatedfoofile', { ask: false }); + expect(fs.readFileSync(`./__tmpfoo.txt`, 'utf-8')).to.equal('updatedfoofile'); + setOverrideAllFiles(false); + }); +}); + +describe('copyTemplates', () => { + it('returns a promise which resolves with the copied and processed files', async () => { + const copiedFiles = await copyTemplates(`./test/template/**/*`, `source`, { + name: 'hello-world', + }); + expect(copiedFiles).to.deep.equal([ + { + processed: "console.log('name: hello-world');\n", + toPath: './source/index.js', + }, + ]); + }); +}); + +describe('copyTemplateJsonInto', () => { + beforeEach(() => { + resetVirtualFiles(); + }); + + it('merges objects', async () => { + writeFileToPath(`source/package.json`, '{ "source": "data" }'); + writeFileToPath(`generator/package.json`, '{ "from": "generator" }'); + copyTemplateJsonInto(`generator/package.json`, 'source/package.json'); + deleteVirtualFile('generator/package.json'); // just used to make test easier + + expect(virtualFiles).to.deep.equal([ + { + path: 'source/package.json', + content: '{\n "source": "data",\n "from": "generator"\n}', + }, + ]); + }); + + it('merges arrays', async () => { + writeFileToPath(`source/package.json`, '{ "array": [1, 2] }'); + writeFileToPath(`generator/package.json`, '{ "array": [3] }'); + copyTemplateJsonInto(`generator/package.json`, 'source/package.json'); + deleteVirtualFile('generator/package.json'); // just used to make test easier + + expect(virtualFiles).to.deep.equal([ + { + path: 'source/package.json', + content: '{\n "array": [\n 1,\n 2,\n 3\n ]\n}', + }, + ]); + }); + + it('can override arrays by setting { mode: "override" } ', async () => { + writeFileToPath(`source/package.json`, '{ "array": [1, 2] }'); + writeFileToPath(`generator/package.json`, '{ "array": [3] }'); + copyTemplateJsonInto( + `generator/package.json`, + 'source/package.json', + {}, + { + mode: 'override', + }, + ); + deleteVirtualFile('generator/package.json'); // just used to make test easier + + expect(virtualFiles).to.deep.equal([ + { + path: 'source/package.json', + content: '{\n "array": [\n 3\n ]\n}', + }, + ]); + }); +}); + +describe('executeMixinGenerator', () => { + it('combines multiple mixins and executes them', async () => { + const FooMixin = subclass => + class extends subclass { + constructor() { + super(); + this.foo = true; + } + }; + + const BarMixin = subclass => + class extends subclass { + constructor() { + super(); + this.bar = true; + } + }; + + const data = {}; + class Base { + execute() { + // @ts-ignore + data.foo = this.foo; + // @ts-ignore + data.bar = this.bar; + data.gotExecuted = true; + } + + // eslint-disable-next-line class-methods-use-this + end() { + data.gotEnded = true; + } + } + + // @ts-ignore + await executeMixinGenerator([FooMixin, BarMixin], {}, Base); + + expect(data).to.deep.equal({ + foo: true, + bar: true, + gotExecuted: true, + gotEnded: true, + }); + }); +}); + +describe('optionsToCommand', () => { + it('supports strings', async () => { + const options = { + type: 'scaffold', + }; + expect(optionsToCommand(options)).to.equal('npm init @open-wc --type scaffold '); + }); + + it('supports numbers', async () => { + const options = { + version: 2, + }; + expect(optionsToCommand(options)).to.equal('npm init @open-wc --version 2 '); + }); + + it('supports boolean', async () => { + const options = { + writeToDisk: true, + }; + expect(optionsToCommand(options)).to.equal('npm init @open-wc --writeToDisk '); + const options2 = { + writeToDisk: false, + }; + expect(optionsToCommand(options2)).to.equal('npm init @open-wc '); + }); + + it('supports arrays', async () => { + const options = { + features: ['testing', 'demoing'], + }; + expect(optionsToCommand(options)).to.equal('npm init @open-wc --features testing demoing '); + }); + + it('converts real example', async () => { + const options = { + type: 'scaffold', + scaffoldType: 'wc', + features: ['testing', 'demoing'], + scaffoldFilesFor: ['testing', 'demoing'], + tagName: 'foo-bar', + installDependencies: 'false', + }; + expect(optionsToCommand(options)).to.equal( + 'npm init @open-wc --type scaffold --scaffoldType wc --features testing demoing --scaffoldFilesFor testing demoing --tagName foo-bar --installDependencies false ', + ); + }); +}); + +describe('filesToTree', () => { + it('renders a single file', async () => { + expect(filesToTree(['./foo.js'])).to.equal(['./', '└── foo.js\n'].join('\n')); + }); + + it('renders two files', async () => { + // prettier-ignore + expect(filesToTree(['./foo.js', './bar.js'])).to.equal([ + './', + '├── foo.js', + '└── bar.js\n', + ].join('\n')); + }); + + it('renders multiple files', async () => { + // prettier-ignore + expect(filesToTree(['./foo.js', './bar.js', './baz.js'])).to.equal([ + './', + '├── foo.js', + '├── bar.js', + '└── baz.js\n', + ].join('\n')); + }); + + it('renders a directory and file', async () => { + // prettier-ignore + expect(filesToTree(['./foo/foo.js'])).to.equal([ + './', + '├── foo/', + '│ └── foo.js\n', + ].join('\n')); + }); + + it('renders a directory and file and root file', async () => { + // prettier-ignore + expect(filesToTree(['./foo/foo.js', './bar.js'])).to.equal([ + './', + '├── foo/', + '│ └── foo.js', + '└── bar.js\n', + ].join('\n')); + }); + + it('renders a nested directory and file', async () => { + // prettier-ignore + expect(filesToTree(['./foo/bar/baz/bong.js'])).to.equal([ + './', + '├── foo/', + '│ ├── bar/', + '│ │ ├── baz/', + '│ │ │ └── bong.js\n', + ].join('\n')); + }); + + it('renders a nested directory and file', async () => { + // prettier-ignore + expect(filesToTree(['./foo/bar.js', './foo/foo.js'])).to.equal([ + './', + '├── foo/', + '│ ├── bar.js', + '│ └── foo.js\n', + ].join('\n')); + }); + + it('renders a nested directory and file', async () => { + // prettier-ignore + expect(filesToTree(['./foo/bar/baz.js', './foo/foo.js'])).to.equal([ + './', + '├── foo/', + '│ ├── bar/', + '│ │ └── baz.js', + '│ └── foo.js\n', + ].join('\n')); + }); + + it('renders an common usecase', async () => { + expect( + filesToTree([ + './foo-bar/src/FooBar.js', + './foo-bar/src/foo-bar.js', + './foo-bar/LICENSE', + './foo-bar/README.md', + ]), + ).to.equal( + [ + './', + '├── foo-bar/', + '│ ├── src/', + '│ │ ├── FooBar.js', + '│ │ └── foo-bar.js', + '│ ├── LICENSE', + '│ └── README.md\n', + ].join('\n'), + ); + }); +}); diff --git a/test/generate-command.js b/test/generate-command.js new file mode 100644 index 0000000..bd37998 --- /dev/null +++ b/test/generate-command.js @@ -0,0 +1,17 @@ +import { join } from 'path'; + +const COMMAND_PATH = join(__dirname, '../src/create.js'); + +export function generateCommand({ destinationPath = '.' } = {}) { + return `node -r @babel/register ${COMMAND_PATH} \ + --destinationPath ${destinationPath} \ + --type scaffold \ + --scaffoldType app \ + --features linting testing demoing building \ + --scaffoldFilesFor testing demoing building \ + --typescript false \ + --tagName scaffold-app \ + --writeToDisk true \ + --installDependencies false + `; +} diff --git a/test/integration.test.js b/test/integration.test.js new file mode 100644 index 0000000..64dbed5 --- /dev/null +++ b/test/integration.test.js @@ -0,0 +1,115 @@ +import _rimraf from 'rimraf'; +import chai from 'chai'; +import chaiFs from 'chai-fs'; +import { exec as _exec } from 'child_process'; +import { promisify } from 'util'; +import { lstatSync, readdirSync, readFileSync } from 'fs'; +import { join } from 'path'; +import { CLIEngine } from 'eslint'; +import { generateCommand } from './generate-command.js'; + +const exec = promisify(_exec); + +const rimraf = promisify(_rimraf); + +const { expect } = chai; + +chai.use(chaiFs); + +const getFileMessages = ({ messages, filePath }) => `${filePath}:\n${messages.join('\n')}`; + +const ACTUAL_PATH = join(process.cwd(), './scaffold-app'); + +/** + * Deletes the test files + */ +async function deleteGenerated() { + await rimraf(ACTUAL_PATH); +} + +/** + * Removes text from the cli output which is specific to the local environment, i.e. the full path to the output dir. + * @param {string} output raw output + * @return {string} cleaned output + */ +function stripUserDir(output) { + return output.replace(/\b(.*)\/scaffold-app/, '/scaffold-app'); +} + +/** + * Asserts that the contents of a file at a path equal the contents of a file at another path + * @param {string} expectedPath path to expected output + * @param {string} actualPath path to actual output + */ +function assertFile(expectedPath, actualPath) { + expect(actualPath).to.be.a.file().and.equal(expectedPath); +} + +/** + * Recursively checks a directory's contents, asserting each file's contents + * matches it's counterpart in a snapshot directory + * @param {string} expectedPath snapshot directory path + * @param {string} actualPath output directory path + */ +function checkSnapshotContents(expectedPath, actualPath) { + readdirSync(actualPath).forEach(filename => { + const actualFilePath = join(actualPath, filename); + const expectedFilePath = join(expectedPath, filename); + return lstatSync(actualFilePath).isDirectory() + ? checkSnapshotContents(expectedFilePath, actualFilePath) + : assertFile(expectedFilePath, actualFilePath); + }); +} + +let stdout; +let stderr; +let EXPECTED_OUTPUT; + +const generate = ({ command, expectedPath }) => + async function generateTestProject() { + ({ stdout, stderr } = await exec(command)); + const EXPECTED_PATH = join(expectedPath, '../fully-loaded-app.output.txt'); + EXPECTED_OUTPUT = readFileSync(EXPECTED_PATH, 'utf-8'); + }; + +describe('create', function create() { + this.timeout(10000); + + // For some reason, this doesn't do anything + const destinationPath = join(__dirname, './output'); + + const expectedPath = join(__dirname, './snapshots/fully-loaded-app'); + + const command = generateCommand({ destinationPath }); + + before(generate({ command, expectedPath })); + + after(deleteGenerated); + + it('scaffolds a fully loaded app project', async () => { + // Check that all files exist, without checking their contents + expect(ACTUAL_PATH).to.be.a.directory().and.deep.equal(expectedPath); + }); + + it('generates expected file contents', () => { + // Check recursively all file contents + checkSnapshotContents(expectedPath, ACTUAL_PATH); + }); + + it.skip('outputs expected message', () => { + expect(stripUserDir(stdout)).to.equal(stripUserDir(EXPECTED_OUTPUT)); + }); + + it('does not exit with an error', () => { + expect(stderr).to.not.be.ok; + }); + + it('generates a project which passes linting', async () => { + const cli = new CLIEngine({ useEslintrc: true }); + // @ts-expect-error: a problem with @types/eslint? + const { errorCount, warningCount, messages = [] } = cli.executeOnFiles([ACTUAL_PATH]); + const prettyOutput = messages.map(getFileMessages).join('\n\n'); + expect(errorCount).to.equal(0, prettyOutput); + expect(warningCount).to.equal(0, prettyOutput); + }); +}); diff --git a/test/snapshots/fully-loaded-app.output.txt b/test/snapshots/fully-loaded-app.output.txt new file mode 100644 index 0000000..cc1e715 --- /dev/null +++ b/test/snapshots/fully-loaded-app.output.txt @@ -0,0 +1,72 @@ + + _.,,,,,,,,,._ + .d'' ``b. Open Web Components Recommendations + .p' Open `q. + .d' Web Components `b. Start or upgrade your web component project with + .d' `b. ease. All our recommendations at your fingertips. + :: ................. :: + `p. .q' See more details at https://open-wc.org/init/ + `p. open-wc.org .q' + `b. @openWc .d' + `q.. ..,' Note: you can exit any time with Ctrl+C or Esc + '',,,,,,,,,,'' + + + +./ +├── scaffold-app/ +│ ├── .storybook/ +│ │ ├── main.js +│ │ └── preview.js +│ ├── components/ +│ │ ├── page-main/ +│ │ │ ├── / +│ │ │ │ ├── demo/ +│ │ │ │ │ └── index.html +│ │ │ │ ├── index.js +│ │ │ │ └── README.md +│ │ │ ├── src/ +│ │ │ │ └── PageMain.js +│ │ │ └── page-main.js +│ │ ├── page-one/ +│ │ │ ├── / +│ │ │ │ ├── demo/ +│ │ │ │ │ └── index.html +│ │ │ │ ├── index.js +│ │ │ │ └── README.md +│ │ │ ├── src/ +│ │ │ │ └── PageOne.js +│ │ │ └── page-one.js +│ │ ├── scaffold-app/ +│ │ │ ├── demo/ +│ │ │ │ └── index.html +│ │ │ ├── src/ +│ │ │ │ ├── open-wc-logo.js +│ │ │ │ ├── ScaffoldApp.js +│ │ │ │ └── templateAbout.js +│ │ │ ├── test/ +│ │ │ │ └── scaffold-app.test.js +│ │ │ ├── index.js +│ │ │ ├── README.md +│ │ │ └── scaffold-app.js +│ ├── .editorconfig +│ ├── .gitignore +│ ├── custom-elements.json +│ ├── index.html +│ ├── web-test-runner.config.js +│ ├── LICENSE +│ ├── package.json +│ ├── README.md +│ └── rollup.config.js + +Writing..... done + +If you want to rerun this exact same generator you can do so by executing: +npm init @open-wc --destinationPath /path/to/open-wc/scaffold-app --type scaffold --scaffoldType app --features linting testing demoing building --buildingType rollup --tagName scaffold-app --writeToDisk true --installDependencies false + +You are all set up now! + +All you need to do is run: + cd scaffold-app + npm run start + diff --git a/test/snapshots/fully-loaded-app/.editorconfig b/test/snapshots/fully-loaded-app/.editorconfig new file mode 100644 index 0000000..c8c2d2a --- /dev/null +++ b/test/snapshots/fully-loaded-app/.editorconfig @@ -0,0 +1,29 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + + +[*] + +# Change these settings to your own preference +indent_style = space +indent_size = 2 + +# We recommend you to keep these unchanged +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false + +[*.json] +indent_size = 2 + +[*.{html,js,md}] +block_comment_start = /** +block_comment = * +block_comment_end = */ diff --git a/test/snapshots/fully-loaded-app/.gitignore b/test/snapshots/fully-loaded-app/.gitignore new file mode 100644 index 0000000..cd190ee --- /dev/null +++ b/test/snapshots/fully-loaded-app/.gitignore @@ -0,0 +1,21 @@ +## editors +/.idea +/.vscode + +## system files +.DS_Store + +## npm +/node_modules/ +/npm-debug.log + +## testing +/coverage/ + +## temp folders +/.tmp/ + +# build +/_site/ +/dist/ +/out-tsc/ \ No newline at end of file diff --git a/test/snapshots/fully-loaded-app/.storybook/main.js b/test/snapshots/fully-loaded-app/.storybook/main.js new file mode 100644 index 0000000..1a4258d --- /dev/null +++ b/test/snapshots/fully-loaded-app/.storybook/main.js @@ -0,0 +1,14 @@ +module.exports = { + stories: ['../**/stories/*.stories.{js,md,mdx}'], + addons: [ + 'storybook-prebuilt/addon-knobs/register.js', + 'storybook-prebuilt/addon-docs/register.js', + 'storybook-prebuilt/addon-viewport/register.js', + ], + esDevServer: { + // custom es-dev-server options + nodeResolve: true, + watch: true, + open: true + }, +}; diff --git a/test/snapshots/fully-loaded-app/.storybook/preview.js b/test/snapshots/fully-loaded-app/.storybook/preview.js new file mode 100644 index 0000000..2cc90bb --- /dev/null +++ b/test/snapshots/fully-loaded-app/.storybook/preview.js @@ -0,0 +1,17 @@ +import { addParameters, setCustomElements } from '@open-wc/demoing-storybook'; + +addParameters({ + docs: { + iframeHeight: '200px', + } +}); + +async function run() { + const customElements = await ( + await fetch(new URL('../custom-elements.json', import.meta.url)) + ).json(); + + setCustomElements(customElements); +} + +run(); diff --git a/test/snapshots/fully-loaded-app/LICENSE b/test/snapshots/fully-loaded-app/LICENSE new file mode 100644 index 0000000..0d3c431 --- /dev/null +++ b/test/snapshots/fully-loaded-app/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 scaffold-app + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/test/snapshots/fully-loaded-app/README.md b/test/snapshots/fully-loaded-app/README.md new file mode 100644 index 0000000..32da54f --- /dev/null +++ b/test/snapshots/fully-loaded-app/README.md @@ -0,0 +1,30 @@ +

+ +

+ +## Open-wc Starter App + +[![Built with open-wc recommendations](https://img.shields.io/badge/built%20with-open--wc-blue.svg)](https://github.com/open-wc) + +## Quickstart + +To get started: + +```bash +npm init @open-wc +# requires node 10 & npm 6 or higher +``` + +## Scripts + +- `start` runs your app for development, reloading on file changes +- `start:build` runs your app after it has been built using the build command +- `build` builds your app and outputs it in your `dist` directory +- `test` runs your test suite with Web Test Runner +- `lint` runs the linter for your project + +## Tooling configs + +For most of the tools, the configuration is in the `package.json` to reduce the amount of files in your project. + +If you customize the configuration a lot, you can consider moving them to individual files. \ No newline at end of file diff --git a/test/snapshots/fully-loaded-app/custom-elements.json b/test/snapshots/fully-loaded-app/custom-elements.json new file mode 100644 index 0000000..5c8564a --- /dev/null +++ b/test/snapshots/fully-loaded-app/custom-elements.json @@ -0,0 +1,26 @@ +{ + "version": 2, + "tags": [ + { + "name": "scaffold-app", + "description": "An application with a title and an action counter", + "properties": [ + { + "name": "title", + "type": "String", + "description": "The title of your application", + "default": "Hey there" + }, + { + "name": "page", + "type": "String", + "description": "Which page to show", + "default": "main" + } + ], + "events": [], + "slots": [], + "cssProperties": [] + } + ] +} diff --git a/test/snapshots/fully-loaded-app/index.html b/test/snapshots/fully-loaded-app/index.html new file mode 100644 index 0000000..6400570 --- /dev/null +++ b/test/snapshots/fully-loaded-app/index.html @@ -0,0 +1,28 @@ + + + + + + + + + + + scaffold-app + + + + + + + + + \ No newline at end of file diff --git a/test/snapshots/fully-loaded-app/package.json b/test/snapshots/fully-loaded-app/package.json new file mode 100644 index 0000000..9c6ec2f --- /dev/null +++ b/test/snapshots/fully-loaded-app/package.json @@ -0,0 +1,64 @@ +{ + "scripts": { + "lint:eslint": "eslint --ext .js,.html . --ignore-path .gitignore", + "format:eslint": "eslint --ext .js,.html . --fix --ignore-path .gitignore", + "lint:prettier": "prettier \"**/*.js\" --check --ignore-path .gitignore", + "format:prettier": "prettier \"**/*.js\" --write --ignore-path .gitignore", + "lint": "npm run lint:eslint && npm run lint:prettier", + "format": "npm run format:eslint && npm run format:prettier", + "test": "web-test-runner --coverage", + "test:watch": "web-test-runner --watch", + "storybook": "start-storybook", + "storybook:build": "build-storybook", + "build": "rimraf dist && rollup -c rollup.config.js", + "start:build": "npm run build && web-dev-server --root-dir dist --app-index index.html --open --compatibility none", + "start": "web-dev-server --app-index index.html --node-resolve --open --watch" + }, + "devDependencies": { + "eslint": "^6.1.0", + "@open-wc/eslint-config": "^2.0.0", + "prettier": "^2.0.4", + "eslint-config-prettier": "^6.11.0", + "husky": "^1.0.0", + "lint-staged": "^10.0.0", + "@web/test-runner": "^0.7.41", + "@open-wc/testing": "^2.0.0", + "@open-wc/demoing-storybook": "^2.0.0", + "@open-wc/building-rollup": "^1.0.0", + "deepmerge": "^4.2.2", + "rimraf": "^2.6.3", + "rollup": "^2.3.4", + "@web/dev-server": "^0.0.12" + }, + "eslintConfig": { + "extends": [ + "@open-wc/eslint-config", + "eslint-config-prettier" + ] + }, + "prettier": { + "singleQuote": true, + "arrowParens": "avoid" + }, + "husky": { + "hooks": { + "pre-commit": "lint-staged" + } + }, + "lint-staged": { + "*.js": [ + "eslint --fix", + "prettier --write", + "git add" + ] + }, + "name": "scaffold-app", + "version": "0.0.0", + "description": "Webcomponent scaffold-app following open-wc recommendations", + "author": "scaffold-app", + "license": "MIT", + "dependencies": { + "lit-html": "^1.0.0", + "lit-element": "^2.0.1" + } +} \ No newline at end of file diff --git a/test/snapshots/fully-loaded-app/rollup.config.js b/test/snapshots/fully-loaded-app/rollup.config.js new file mode 100644 index 0000000..babc0bf --- /dev/null +++ b/test/snapshots/fully-loaded-app/rollup.config.js @@ -0,0 +1,31 @@ +import merge from 'deepmerge'; +// use createSpaConfig for bundling a Single Page App +import { createSpaConfig } from '@open-wc/building-rollup'; + +// use createBasicConfig to do regular JS to JS bundling +// import { createBasicConfig } from '@open-wc/building-rollup'; + +const baseConfig = createSpaConfig({ + // use the outputdir option to modify where files are output + // outputDir: 'dist', + + // if you need to support older browsers, such as IE11, set the legacyBuild + // option to generate an additional build just for this browser + // legacyBuild: true, + + // development mode creates a non-minified build for debugging or development + developmentMode: process.env.ROLLUP_WATCH === 'true', + + // set to true to inject the service worker registration into your index.html + injectServiceWorker: false, +}); + +export default merge(baseConfig, { + // if you use createSpaConfig, you can use your index.html as entrypoint, + // any