├── .bowerrc ├── .editorconfig ├── .ember-cli ├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .npmignore ├── .template-lintrc.js ├── .watchmanconfig ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── addon ├── initializers │ ├── component-styles.js │ └── route-styles.js ├── instance-initializers │ └── route-styles.js ├── mixins │ └── style-namespacing-extras.js ├── pod-names.js └── utils │ └── init-route-styles.js ├── app ├── initializers │ ├── component-styles.js │ └── route-styles.js ├── instance-initializers │ └── route-styles.js └── mixins │ └── style-namespacing-extras.js ├── bin └── install-test-addons.js ├── config ├── ember-try.js └── environment.js ├── ember-cli-build.js ├── index.js ├── lib ├── component-names.js ├── pod-names.js ├── pod-style.js └── preprocess-class-names.js ├── package.json ├── testem.js ├── tests ├── .eslintrc.js ├── acceptance │ ├── aborted-state-test.js │ ├── addon-less-test.js │ ├── addon-scss-test.js │ ├── classic-structure-test.js │ ├── css-test.js │ ├── error-state-test.js │ ├── less-test.js │ ├── loading-state-test.js │ ├── no-style-files-yet-test.js │ ├── query-params-test.js │ ├── sass-test.js │ ├── scss-test.js │ ├── styl-test.js │ ├── template-style-only-test.js │ └── unique-component-paths-test.js ├── dummy │ ├── app │ │ ├── aborted-state │ │ │ ├── route.js │ │ │ └── template.hbs │ │ ├── addon │ │ │ ├── less │ │ │ │ └── template.hbs │ │ │ └── scss │ │ │ │ └── template.hbs │ │ ├── app.js │ │ ├── components │ │ │ ├── base-rules │ │ │ │ ├── component.js │ │ │ │ └── template.hbs │ │ │ ├── css │ │ │ │ └── base-rules │ │ │ │ │ ├── component.js │ │ │ │ │ └── styles.css │ │ │ ├── less │ │ │ │ └── base-rules │ │ │ │ │ ├── component.js │ │ │ │ │ └── styles.less │ │ │ ├── sass │ │ │ │ └── base-rules │ │ │ │ │ ├── component.js │ │ │ │ │ └── styles.sass │ │ │ ├── scss │ │ │ │ ├── base-rules │ │ │ │ │ ├── component.js │ │ │ │ │ └── styles.scss │ │ │ │ └── for-loop │ │ │ │ │ ├── component.js │ │ │ │ │ ├── styles.scss │ │ │ │ │ └── template.hbs │ │ │ ├── styl │ │ │ │ └── base-rules │ │ │ │ │ ├── component.js │ │ │ │ │ └── styles.styl │ │ │ └── template-and-style │ │ │ │ ├── styles.scss │ │ │ │ └── template.hbs │ │ ├── css │ │ │ ├── nested │ │ │ │ └── styles.css │ │ │ ├── styles.css │ │ │ └── template.hbs │ │ ├── error-state │ │ │ ├── handled │ │ │ │ └── route.js │ │ │ ├── styles.scss │ │ │ └── template.hbs │ │ ├── index.html │ │ ├── less │ │ │ ├── nested │ │ │ │ └── styles.less │ │ │ ├── styles.less │ │ │ └── template.hbs │ │ ├── loading-state │ │ │ ├── base │ │ │ │ ├── styles.scss │ │ │ │ └── template.hbs │ │ │ ├── waiting-loading │ │ │ │ ├── styles.scss │ │ │ │ └── template.hbs │ │ │ └── waiting │ │ │ │ ├── route.js │ │ │ │ ├── styles.scss │ │ │ │ └── template.hbs │ │ ├── no-style-files-yet │ │ │ └── template.hbs │ │ ├── query-params │ │ │ ├── controller.js │ │ │ ├── route.js │ │ │ ├── styles.scss │ │ │ └── template.hbs │ │ ├── resolver.js │ │ ├── router.js │ │ ├── sass │ │ │ ├── nested │ │ │ │ └── styles.sass │ │ │ ├── styles.sass │ │ │ └── template.hbs │ │ ├── scss │ │ │ ├── nested │ │ │ │ └── styles.scss │ │ │ ├── styles.scss │ │ │ └── template.hbs │ │ ├── styl │ │ │ ├── nested │ │ │ │ └── styles.styl │ │ │ ├── styles.styl │ │ │ └── template.hbs │ │ ├── styles │ │ │ ├── app.css │ │ │ ├── app.less │ │ │ ├── app.sass │ │ │ ├── app.scss │ │ │ ├── app.styl │ │ │ └── component-styles │ │ │ │ ├── classic-structure.scss │ │ │ │ └── nested │ │ │ │ └── classic-structure-nested.scss │ │ ├── template-style-only │ │ │ └── template.hbs │ │ ├── templates │ │ │ ├── application.hbs │ │ │ ├── classic-structure-nested.hbs │ │ │ ├── classic-structure.hbs │ │ │ └── components │ │ │ │ ├── classic-structure.hbs │ │ │ │ └── nested │ │ │ │ └── classic-structure-nested.hbs │ │ └── unique-component-paths │ │ │ ├── -components │ │ │ └── test-component │ │ │ │ ├── styles.scss │ │ │ │ └── template.hbs │ │ │ └── template.hbs │ ├── config │ │ ├── environment.js │ │ ├── optional-features.json │ │ └── targets.js │ ├── lib │ │ ├── no-style-files-yet │ │ │ ├── addon │ │ │ │ └── components │ │ │ │ │ └── no-style │ │ │ │ │ ├── component.js │ │ │ │ │ └── template.hbs │ │ │ ├── app │ │ │ │ └── components │ │ │ │ │ └── no-style │ │ │ │ │ └── component.js │ │ │ ├── index.js │ │ │ └── package.json │ │ ├── second-test-addon │ │ │ ├── addon │ │ │ │ ├── components │ │ │ │ │ └── second-addon-less │ │ │ │ │ │ ├── component.js │ │ │ │ │ │ ├── styles.less │ │ │ │ │ │ └── template.hbs │ │ │ │ └── styles │ │ │ │ │ └── addon.less │ │ │ ├── app │ │ │ │ └── components │ │ │ │ │ └── second-addon-less │ │ │ │ │ └── component.js │ │ │ ├── index.js │ │ │ └── package.json │ │ └── test-addon │ │ │ ├── addon │ │ │ ├── components │ │ │ │ └── addon-scss │ │ │ │ │ ├── component.js │ │ │ │ │ ├── styles.scss │ │ │ │ │ └── template.hbs │ │ │ └── styles │ │ │ │ └── addon.scss │ │ │ ├── app │ │ │ └── components │ │ │ │ └── addon-scss │ │ │ │ └── component.js │ │ │ ├── index.js │ │ │ └── package.json │ └── public │ │ ├── crossdomain.xml │ │ └── robots.txt ├── helpers │ ├── destroy-app.js │ ├── module-for-acceptance.js │ ├── resolver.js │ └── start-app.js ├── index.html └── test-helper.js └── yarn.lock /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components", 3 | "analytics": false 4 | } 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | indent_style = space 14 | indent_size = 2 15 | 16 | [*.hbs] 17 | insert_final_newline = false 18 | 19 | [*.{diff,md}] 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /.ember-cli: -------------------------------------------------------------------------------- 1 | { 2 | "usePods": true, 3 | /** 4 | Ember CLI sends analytics information by default. The data is completely 5 | anonymous, but there are times when you might want to disable this behavior. 6 | 7 | Setting `disableAnalytics` to true will prevent any data from being sent. 8 | */ 9 | "disableAnalytics": false 10 | } 11 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # unconventional js 2 | /blueprints/*/files/ 3 | /vendor/ 4 | 5 | # compiled output 6 | /dist/ 7 | /tmp/ 8 | 9 | # dependencies 10 | /bower_components/ 11 | /node_modules/ 12 | 13 | # misc 14 | /coverage/ 15 | !.* 16 | 17 | # ember-try 18 | /.node_modules.ember-try/ 19 | /bower.json.ember-try 20 | /package.json.ember-try 21 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | ecmaVersion: 2017, 5 | sourceType: 'module' 6 | }, 7 | plugins: [ 8 | 'ember' 9 | ], 10 | extends: [ 11 | 'eslint:recommended', 12 | 'plugin:ember/recommended' 13 | ], 14 | env: { 15 | browser: true 16 | }, 17 | rules: { 18 | }, 19 | overrides: [ 20 | // node files 21 | { 22 | files: [ 23 | '.eslintrc.js', 24 | '.template-lintrc.js', 25 | 'ember-cli-build.js', 26 | 'index.js', 27 | 'testem.js', 28 | 'blueprints/*/index.js', 29 | 'config/**/*.js', 30 | 'tests/dummy/config/**/*.js' 31 | ], 32 | excludedFiles: [ 33 | 'addon/**', 34 | 'addon-test-support/**', 35 | 'app/**', 36 | 'tests/dummy/app/**' 37 | ], 38 | parserOptions: { 39 | sourceType: 'script', 40 | ecmaVersion: 2015 41 | }, 42 | env: { 43 | browser: false, 44 | node: true 45 | }, 46 | plugins: ['node'], 47 | rules: Object.assign({}, require('eslint-plugin-node').configs.recommended.rules, { 48 | // add your custom rules and overrides for node files here 49 | }) 50 | } 51 | ] 52 | }; 53 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - master 8 | tags: 9 | - v* 10 | pull_request: {} 11 | 12 | concurrency: 13 | group: ci-${{ github.head_ref || github.ref }} 14 | cancel-in-progress: true 15 | 16 | jobs: 17 | test: 18 | name: "Tests" 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - uses: actions/checkout@v2 23 | - name: Install Node 24 | uses: actions/setup-node@v2 25 | with: 26 | node-version: 12.x 27 | cache: yarn 28 | - name: Install Dependencies 29 | run: yarn install --frozen-lockfile 30 | - name: Lint 31 | run: yarn lint:js && yarn lint:hbs 32 | - name: Run Tests 33 | run: yarn test 34 | 35 | # floating: 36 | # name: "Floating Dependencies" 37 | # runs-on: ubuntu-latest 38 | 39 | # steps: 40 | # - uses: actions/checkout@v2 41 | # - uses: actions/setup-node@v2 42 | # with: 43 | # node-version: 12.x 44 | # cache: yarn 45 | # - name: Install Dependencies 46 | # run: yarn install --no-lockfile 47 | # - name: Run Tests 48 | # run: yarn test 49 | 50 | try-scenarios: 51 | name: ${{ matrix.try-scenario }} 52 | runs-on: ubuntu-latest 53 | needs: 'test' 54 | 55 | strategy: 56 | fail-fast: false 57 | matrix: 58 | try-scenario: 59 | - ember-lts-2.16 60 | - ember-lts-2.18 61 | # - ember-lts-3.24 62 | # - ember-lts-3.28 63 | # - ember-release 64 | # - ember-beta 65 | # - ember-canary 66 | # - ember-classic 67 | # - embroider-safe 68 | # - embroider-optimized 69 | 70 | steps: 71 | - uses: actions/checkout@v2 72 | - name: Install Node 73 | uses: actions/setup-node@v2 74 | with: 75 | node-version: 12.x 76 | cache: yarn 77 | - name: Install Dependencies 78 | run: yarn install --frozen-lockfile 79 | - name: Run Tests 80 | run: ./node_modules/.bin/ember try:one ${{ matrix.try-scenario }} 81 | 82 | publish: 83 | name: Publish 84 | if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') 85 | runs-on: ubuntu-latest 86 | needs: 'test' 87 | 88 | steps: 89 | - name: Checkout 90 | uses: actions/checkout@v2 91 | - name: Install Node 92 | uses: actions/setup-node@v2 93 | with: 94 | node-version: 12.x 95 | cache: yarn 96 | # This creates an .npmrc that reads the NODE_AUTH_TOKEN environment variable 97 | registry-url: 'https://registry.npmjs.org' 98 | 99 | - name: Install Dependencies 100 | run: yarn install --frozen-lockfile 101 | 102 | - name: Publish to npm 103 | run: npm publish 104 | env: 105 | NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} 106 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist/ 5 | /tmp/ 6 | 7 | # dependencies 8 | /bower_components/ 9 | /node_modules/ 10 | 11 | # misc 12 | /.sass-cache 13 | /connect.lock 14 | /coverage/ 15 | /libpeerconnection.log 16 | /npm-debug.log* 17 | /testem.log 18 | /yarn-error.log 19 | 20 | # ember-try 21 | /.node_modules.ember-try/ 22 | /bower.json.ember-try 23 | /package.json.ember-try 24 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist/ 3 | /tmp/ 4 | 5 | # dependencies 6 | /bower_components/ 7 | 8 | # misc 9 | /.bowerrc 10 | /.editorconfig 11 | /.ember-cli 12 | /.eslintignore 13 | /.eslintrc.js 14 | /.github 15 | /.gitignore 16 | /.template-lintrc.js 17 | /.travis.yml 18 | /.watchmanconfig 19 | /bower.json 20 | /config/ember-try.js 21 | /CONTRIBUTING.md 22 | /ember-cli-build.js 23 | /testem.js 24 | /tests/ 25 | /yarn.lock 26 | .gitkeep 27 | 28 | # ember-try 29 | /.node_modules.ember-try/ 30 | /bower.json.ember-try 31 | /package.json.ember-try 32 | -------------------------------------------------------------------------------- /.template-lintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | extends: 'recommended' 5 | }; 6 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": ["tmp", "dist"] 3 | } 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | 6 | ## [0.8.1](https://github.com/ebryn/ember-component-css/compare/v0.8.0...v0.8.1) (2022-05-09) 7 | 8 | 9 | 10 | 11 | # [0.8.0](https://github.com/ebryn/ember-component-css/compare/v0.7.5...v0.8.0) (2022-05-09) 12 | 13 | 14 | 15 | 16 | ## [0.7.5](https://github.com/ebryn/ember-component-css/compare/v0.7.4...v0.7.5) (2022-05-09) 17 | 18 | 19 | 20 | 21 | ## [0.7.4](https://github.com/ebryn/ember-component-css/compare/v0.7.3...v0.7.4) (2019-06-24) 22 | 23 | 24 | ### Bug Fixes 25 | 26 | * **route-styles:** making sure that the route info object has the right shape before continuing fixs [#323](https://github.com/ebryn/ember-component-css/issues/323) ([6a90a5b](https://github.com/ebryn/ember-component-css/commit/6a90a5b)) 27 | 28 | 29 | 30 | 31 | ## [0.7.3](https://github.com/ebryn/ember-component-css/compare/v0.7.2...v0.7.3) (2019-06-22) 32 | 33 | 34 | ### Bug Fixes 35 | 36 | * **route styles:** sometimes there is no 'to' in a route, and so we need to gaurd against that. fixes [#323](https://github.com/ebryn/ember-component-css/issues/323) ([157388d](https://github.com/ebryn/ember-component-css/commit/157388d)) 37 | 38 | 39 | 40 | 41 | ## [0.7.2](https://github.com/ebryn/ember-component-css/compare/v0.7.1...v0.7.2) (2019-06-11) 42 | 43 | 44 | ### Bug Fixes 45 | 46 | * **broken transition:** there's a chance that at times a transition will not have a 'to', so handling that case ([756e89e](https://github.com/ebryn/ember-component-css/commit/756e89e)) 47 | 48 | 49 | 50 | 51 | ## [0.7.1](https://github.com/ebryn/ember-component-css/compare/v0.7.0...v0.7.1) (2019-06-10) 52 | 53 | 54 | 55 | 56 | # [0.7.0](https://github.com/ebryn/ember-component-css/compare/v0.6.9...v0.7.0) (2019-06-03) 57 | 58 | 59 | ### Bug Fixes 60 | 61 | * **loading-route-styleNamespaces:** we needed to hack around and add in some extra hooks to take care of loading routes ([04db211](https://github.com/ebryn/ember-component-css/commit/04db211)) 62 | 63 | 64 | 65 | 66 | ## [0.6.9](https://github.com/ebryn/ember-component-css/compare/v0.6.8...v0.6.9) (2019-05-23) 67 | 68 | 69 | 70 | 71 | ## [0.6.8](https://github.com/ebryn/ember-component-css/compare/v0.6.7...v0.6.8) (2019-05-23) 72 | 73 | 74 | ### Bug Fixes 75 | 76 | * **addon support:** setting the '_allPodStyles' on the host application to hopefully avoid issues with multiple copys ([7e00c02](https://github.com/ebryn/ember-component-css/commit/7e00c02)) 77 | 78 | 79 | 80 | 81 | ## [0.6.7](https://github.com/ebryn/ember-component-css/compare/v0.6.5...v0.6.7) (2019-01-19) 82 | 83 | 84 | ### Bug Fixes 85 | 86 | * **deprication:** updated to fix the outdated merge and use object.assign instead ([8b46279](https://github.com/ebryn/ember-component-css/commit/8b46279)) 87 | * **sass support:** latest sass now throws an eerro if semi colons are presnet, removing them from the style manifest. fixes issue [#301](https://github.com/ebryn/ember-component-css/issues/301) ([697e48c](https://github.com/ebryn/ember-component-css/commit/697e48c)) 88 | 89 | 90 | 91 | 92 | ## [0.6.5](https://github.com/ebryn/ember-component-css/compare/v0.6.4...v0.6.5) (2018-09-10) 93 | 94 | 95 | 96 | 97 | ## [0.6.4](https://github.com/ebryn/ember-component-css/compare/v0.6.3...v0.6.4) (2018-06-20) 98 | 99 | 100 | 101 | 102 | ## [0.6.3](https://github.com/ebryn/ember-component-css/compare/v0.6.2...v0.6.3) (2018-02-26) 103 | 104 | 105 | ### Bug Fixes 106 | 107 | * **ember inspector:** Mixins created with an empty create breaks ember-inspector fixes [#275](https://github.com/ebryn/ember-component-css/issues/275) ([5533674](https://github.com/ebryn/ember-component-css/commit/5533674)) 108 | 109 | 110 | 111 | 112 | ## [0.6.2](https://github.com/ebryn/ember-component-css/compare/v0.6.1...v0.6.2) (2018-02-06) 113 | 114 | 115 | ### Bug Fixes 116 | 117 | * **module imports:** moved functionality that belonged to just the addon, over to the addon. fix [#259](https://github.com/ebryn/ember-component-css/issues/259) ([c016731](https://github.com/ebryn/ember-component-css/commit/c016731)) 118 | 119 | 120 | 121 | 122 | ## [0.6.1](https://github.com/ebryn/ember-component-css/compare/v0.6.0...v0.6.1) (2018-01-30) 123 | 124 | 125 | ### Bug Fixes 126 | 127 | * **router:** accidentally removed a import super call in the routers didTransition. fixes [#266](https://github.com/ebryn/ember-component-css/issues/266) ([446a368](https://github.com/ebryn/ember-component-css/commit/446a368)) 128 | 129 | 130 | 131 | 132 | # [0.6.0](https://github.com/ebryn/ember-component-css/compare/v0.5.0...v0.6.0) (2018-01-26) 133 | 134 | 135 | 136 | 137 | # [0.5.0](https://github.com/ebryn/ember-component-css/compare/v0.4.0...v0.5.0) (2017-11-17) 138 | 139 | 140 | ### Features 141 | 142 | * **styleNamespace:** now upgrading to using 'styleNamespace' for the namespace computed property. Will offically deprecate componentCssClassName in the future ([#254](https://github.com/ebryn/ember-component-css/issues/254)) ([4bb72f9](https://github.com/ebryn/ember-component-css/commit/4bb72f9)) 143 | 144 | 145 | 146 | 147 | # [0.4.0](https://github.com/ebryn/ember-component-css/compare/v0.3.7...v0.4.0) (2017-11-15) 148 | 149 | 150 | ### Features 151 | 152 | * **route-namesapce:** Enable name-spacing of route styles ([114fe3b](https://github.com/ebryn/ember-component-css/commit/114fe3b)) 153 | * **route-namespace:** added documentation about an individual controllers styleNamespace property ([cb94979](https://github.com/ebryn/ember-component-css/commit/cb94979)) 154 | 155 | 156 | 157 | 158 | ## [0.3.7](https://github.com/ebryn/ember-component-css/compare/v0.3.6...v0.3.7) (2017-11-02) 159 | 160 | 161 | ### Features 162 | 163 | * **manifest ordering:** updated broccoli style manifest to now have the order of files in the manifest be sorted first by depth, then by alphanumeric ([fd710bf](https://github.com/ebryn/ember-component-css/commit/fd710bf)) 164 | 165 | 166 | 167 | 168 | ## [0.3.6](https://github.com/ebryn/ember-component-css/compare/v0.3.5...v0.3.6) (2017-11-01) 169 | 170 | 171 | 172 | 173 | ## [0.3.5](https://github.com/ebryn/ember-component-css/compare/v0.3.4...v0.3.5) (2017-07-31) 174 | 175 | 176 | ### Bug Fixes 177 | 178 | * **component name parsing:** only switching out the word 'component/' if it is what starts the path, not for nest options. This should be revisited with unification Closes [#236](https://github.com/ebryn/ember-component-css/issues/236) ([54e087e](https://github.com/ebryn/ember-component-css/commit/54e087e)) 179 | 180 | 181 | 182 | 183 | ## [0.3.4](https://github.com/ebryn/ember-component-css/compare/v0.3.3...v0.3.4) (2017-06-01) 184 | 185 | 186 | ### Bug Fixes 187 | 188 | * **ensure environment:** getting the 'root host', and using a shim if the find host method isn't present, Closes [#231](https://github.com/ebryn/ember-component-css/issues/231) ([09fa5ec](https://github.com/ebryn/ember-component-css/commit/09fa5ec)) 189 | 190 | 191 | 192 | 193 | ## [0.3.3](https://github.com/ebryn/ember-component-css/compare/v0.3.2...v0.3.3) (2017-04-24) 194 | 195 | 196 | 197 | 198 | ## [0.3.2](https://github.com/ebryn/ember-component-css/compare/v0.3.1...v0.3.2) (2017-04-05) 199 | 200 | 201 | ### Bug Fixes 202 | 203 | * **style manifest:** updated to new brocoli-style-mainifest properties that are more explicit ([5e848ca](https://github.com/ebryn/ember-component-css/commit/5e848ca)) 204 | 205 | 206 | ### Features 207 | 208 | * **optimization:** ability to use terse class names to reduce css size ([d53ead8](https://github.com/ebryn/ember-component-css/commit/d53ead8)) 209 | 210 | 211 | 212 | 213 | ## [0.3.1](https://github.com/ebryn/ember-component-css/compare/v0.3.0...v0.3.1) (2017-03-30) 214 | 215 | 216 | ### Bug Fixes 217 | 218 | * **npm dependencies:** published what was being used to compile multiple differnt css preprocessors into one. closes [#221](https://github.com/ebryn/ember-component-css/issues/221) ([a060942](https://github.com/ebryn/ember-component-css/commit/a060942)) 219 | 220 | 221 | 222 | 223 | # [0.3.0](https://github.com/ebryn/ember-component-css/compare/v0.2.12...v0.3.0) (2017-02-25) 224 | 225 | 226 | ### Features 227 | 228 | * **extensible identifier:** moved the generation of the namespace identifier and if the class should be added to a mixin for easier extensibility ([e3c627b](https://github.com/ebryn/ember-component-css/commit/e3c627b)) 229 | 230 | 231 | 232 | 233 | ## [0.2.12](https://github.com/ebryn/ember-component-css/compare/v0.2.11...v0.2.12) (2017-02-24) 234 | 235 | 236 | ### Bug Fixes 237 | 238 | * **description:** removed pod specificity ([16eae3b](https://github.com/ebryn/ember-component-css/commit/16eae3b)) 239 | * **scss @ rules:** now allowing namespaceing of rules deinfed inside of a scss @ for rule. Fixes [#216](https://github.com/ebryn/ember-component-css/issues/216) ([6840c5e](https://github.com/ebryn/ember-component-css/commit/6840c5e)) 240 | 241 | 242 | 243 | 244 | ## [0.2.11](https://github.com/ebryn/ember-component-css/compare/v0.2.10...v0.2.11) (2017-02-03) 245 | 246 | 247 | ### Bug Fixes 248 | 249 | * **documentation:** updated for readabitlity ([d354534](https://github.com/ebryn/ember-component-css/commit/d354534)) 250 | 251 | 252 | 253 | 254 | ## [0.2.10](https://github.com/ebryn/ember-component-css/compare/v0.2.9...v0.2.10) (2017-01-26) 255 | 256 | 257 | ### Bug Fixes 258 | 259 | * **plain css:** Due to the odd nature of 'glob', you can't have a set of just one item. ([fd0d770](https://github.com/ebryn/ember-component-css/commit/fd0d770)), closes [#178](https://github.com/ebryn/ember-component-css/issues/178) [#204](https://github.com/ebryn/ember-component-css/issues/204) 260 | 261 | 262 | 263 | 264 | ## [0.2.9](https://github.com/ebryn/ember-component-css/compare/v0.2.8...v0.2.9) (2017-01-16) 265 | 266 | 267 | ### Bug Fixes 268 | 269 | * **nested addons:** no longer switching to the parent app so that addon's specific settings can be used ([849a72d](https://github.com/ebryn/ember-component-css/commit/849a72d)) 270 | 271 | 272 | 273 | 274 | ## [0.2.8](https://github.com/ebryn/ember-component-css/compare/v0.2.7...v0.2.8) (2016-12-14) 275 | 276 | 277 | 278 | 279 | ## [0.2.7](https://github.com/ebryn/ember-component-css/compare/v0.2.6...v0.2.7) (2016-12-01) 280 | 281 | 282 | ### Bug Fixes 283 | 284 | * **namespacing:** no longer namespacing children of @ rules ([489f23f](https://github.com/ebryn/ember-component-css/commit/489f23f)), closes [#191](https://github.com/ebryn/ember-component-css/issues/191) 285 | 286 | 287 | 288 | 289 | ## [0.2.6](https://github.com/ebryn/ember-component-css/compare/v0.2.5...v0.2.6) (2016-12-01) 290 | 291 | 292 | ### Bug Fixes 293 | 294 | * **ember-2.11:** moving to concatenating and reassigning the classnames in case a classname is already in the array before the init call per [@rwjblue](https://github.com/rwjblue) suggestion ([40113e6](https://github.com/ebryn/ember-component-css/commit/40113e6)) 295 | 296 | 297 | 298 | 299 | ## [0.2.5](https://github.com/ebryn/ember-component-css/compare/v0.2.4...v0.2.5) (2016-12-01) 300 | 301 | 302 | ### Bug Fixes 303 | 304 | * **ember-2.11:** now not pushing to the frozen classnames property, but reasigning it ([63274c0](https://github.com/ebryn/ember-component-css/commit/63274c0)) 305 | 306 | 307 | 308 | 309 | ## [0.2.4](https://github.com/ebryn/ember-component-css/compare/v0.2.3...v0.2.4) (2016-11-22) 310 | 311 | 312 | 313 | 314 | ## [0.2.3](https://github.com/ebryn/ember-component-css/compare/v0.2.2...v0.2.3) (2016-11-15) 315 | 316 | 317 | 318 | 319 | ## [0.2.2](https://github.com/ebryn/ember-component-css/compare/v0.2.1...v0.2.2) (2016-11-05) 320 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How To Contribute 2 | 3 | ## Installation 4 | 5 | * `git clone ` 6 | * `cd my-addon` 7 | * `npm install` 8 | 9 | ## Linting 10 | 11 | * `npm run lint:hbs` 12 | * `npm run lint:js` 13 | * `npm run lint:js -- --fix` 14 | 15 | ## Running tests 16 | 17 | * `ember test` – Runs the test suite on the current Ember version 18 | * `ember test --server` – Runs the test suite in "watch mode" 19 | * `ember try:each` – Runs the test suite against multiple Ember versions 20 | 21 | ## Running the dummy application 22 | 23 | * `ember serve` 24 | * Visit the dummy application at [http://localhost:4200](http://localhost:4200). 25 | 26 | For more information on using ember-cli, visit [https://ember-cli.com/](https://ember-cli.com/). -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ember-component-css [![Build Status](https://github.com/ebryn/ember-component-css/actions/workflows/ci.yml/badge.svg)](https://github.com/ebryn/ember-component-css/actions/workflows/ci.yml) [![Ember Observer Score](https://emberobserver.com/badges/ember-component-css.svg)](https://emberobserver.com/addons/ember-component-css) 2 | 3 | An Ember CLI addon which allows you to specify component-specific style sheets in an app, addon, engine, or in-repo addon. 4 | 5 | Contributions are welcome! Feel free to open up a pull request or issue, and join the **#e-component-css** channel on the [official Ember Discord server](https://discord.gg/zT3asNS) if you have further questions, concerns, or ideas. Thanks! :smile: 6 | 7 | ## Installation 8 | 9 | `ember install ember-component-css` 10 | 11 | ## Usage 12 | 13 | Rules defined in the style-sheets will automatically be namespaced with an autogenerated class. That autogenerated class will also be injected into your component's `classNames` property. This enables you to worry less about rules clashing across component styles. 14 | 15 | For example, given this `app/my-component/styles.scss` file for 'pods', 16 | 17 | or this `app/styles/component-styles/my-component.scss` file for 'classic': 18 | 19 | ```scss 20 | & { // ampersand refers to the component itself (parent selector) 21 | padding: 2px; 22 | } 23 | .urgent { 24 | color: red; 25 | 26 | span { 27 | text-decoration: underline; 28 | } 29 | } 30 | ``` 31 | 32 | Your generated CSS output will look something like: 33 | 34 | ```css 35 | .__my-component__a34fba { 36 | padding: 2px; 37 | } 38 | .__my-component__a34fba .urgent { 39 | color: red; 40 | } 41 | .__my-component__a34fba .urgent span { 42 | text-decoration: underline; 43 | } 44 | ``` 45 | 46 | A typical component invocation that looks like this: 47 | 48 | `{{my-component}}` 49 | 50 | will generated markup like: 51 | 52 | `
` 53 | 54 | ### Inclusion 55 | 56 | To use this addon you *MUST*, import `pod-styles` into your base stylesheet. 57 | 58 | ```scss 59 | // app/styles/app.scss 60 | @import "pod-styles"; 61 | ``` 62 | 63 | ```scss 64 | // app/styles/app.less 65 | @import "pod-styles"; 66 | ``` 67 | 68 | ```scss 69 | // app/styles/app.styl 70 | @import 'pod-styles' 71 | ``` 72 | 73 | ```css 74 | /* app/styles/app.css */ 75 | @import "pod-styles.css"; 76 | ``` 77 | 78 | And that is it! The `pod-styles` file is generated during the build and will then be pulled into your other stylesheet to be processed like normal. 79 | 80 | Note: If you are using more than one type of component style files (ie a .less file and a .scss file) then you will need to add the extension to the @import. Otherwise the extension can be left off. 81 | 82 | ### Usage with pods structure 83 | 84 | To use this with pods, you just need to include a style file in your component pods directory alongside your `template.hbs` or `component.js` files. 85 | 86 | ### Usage with routes 87 | 88 | To use this with routes you need to use pods for the routes and modify the `application.hbs` template a little bit. 89 | Let's assume your `application.hbs` template looks like this: 90 | 91 | ```hbs 92 | {{outlet}} 93 | ``` 94 | 95 | To be able to use this for routes, you need to add a wrapping `div` around the outlet: 96 | 97 | ```hbs 98 |
99 | {{outlet}} 100 |
101 | ``` 102 | 103 | After that it's quite easy: add a style file in your route directory alongside your `route.js` or `template.hbs` files. 104 | 105 | An individual controller also has access to a `styleNamespace` property that is the namespace for a given route. This can be used for various use cases. (like enabling BEM style similar to how the `styleNamespace` is used in a component) 106 | 107 | ### Usage with classic (non pod) structure 108 | 109 | You can use classic Ember app structure by placing component styles in 110 | `app/styles/component-styles`. Name your style files after the component name, 111 | for example `my-component.scss`. The directory where styles are fetched from can 112 | be configured as shown [below](#configuration). It's possible to use a mixture 113 | of classic and pod structured styles in the same app, if you use both styles for 114 | the same component both are included but the pod style will take precedence. 115 | 116 | ### Use in addons 117 | In order to use this inside of an addon, you need to add your style files inside of the components in the 118 | addon directory. You will then be able to import the 'pod-styles' file inside of your addon style file which 119 | is in the `/addon/styles` directory. These styles will then be added to the `vendor.css` file like normal. 120 | 121 | If you are using classic (non pod) structure, your addon directory structure might look like: 122 | ``` 123 | yourAddonDirectory 124 | │ index.js 125 | │ ... etc 126 | └───addon 127 | │ └───components 128 | │ │ yourAddonComponent.js 129 | │ └───templates 130 | │ │ yourAddonComponent.hbs 131 | │ └───styles 132 | │ │ addon.scss (includes the 'pod-styles' import) 133 | │ └───component-styles (this dir name is configurable) 134 | │ │ yourAddonComponent.scss 135 | └───app 136 | └───components 137 | │ yourAddonComponent.js 138 | ``` 139 | 140 | If you are extending the `include` method in your addon, please make sure you call the super like this 141 | ```js 142 | included: function(app) { 143 | this._super.included.apply(this, arguments); 144 | ... 145 | } 146 | ``` 147 | 148 | Be sure "ember-component-css" is listed under the "dependencies" key of your addon's `package.json` file, rather than "devDependencies". Don't forget, if you are using `ember-cli-sass` for your addon's styles, it will need to be in "dependencies" as well. 149 | 150 | Finally, if your addon is compiling the expected CSS into the host's `vendor.css` output, but the expected classes are not being set on your components' HTML elements, you will need to [run your addon _after_ ember-component-css](https://ember-cli.com/extending/#configuring-your-ember-addon-properties): 151 | ```js 152 | // package.json 153 | { 154 | // ... 155 | "dependencies": { 156 | // ... 157 | "ember-component-css": ">= 0.6.4", 158 | // ... 159 | }, 160 | // ... 161 | "ember-addon": { 162 | "configPath": "tests/dummy/config", 163 | "after": "ember-component-css" 164 | } 165 | } 166 | ``` 167 | 168 | ### Plain css usage 169 | In order to use this with plain css files, you need to install [`ember-cli-postcss`](https://github.com/jeffjewiss/ember-cli-postcss) and configure it with [`postcss-import`](https://github.com/postcss/postcss-import). 170 | 171 | ``` 172 | ember install ember-component-css 173 | ember install ember-cli-postcss 174 | npm install postcss-import --save-dev 175 | ``` 176 | Then in your `ember-cli-build.js` you can configure it as such. 177 | ```js 178 | var EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); 179 | var CssImport = require('postcss-import'); 180 | 181 | module.exports = function(defaults) { 182 | var app = new EmberAddon(defaults, { 183 | postcssOptions: { 184 | compile: { 185 | enabled: true, 186 | plugins: [{ 187 | module: CssImport, 188 | }] 189 | } 190 | } 191 | }); 192 | 193 | return app.toTree(); 194 | }; 195 | ``` 196 | 197 | You can also add in [`postcss-cssnext`](https://github.com/MoOx/postcss-cssnext) or any other 198 | postcss plugins in this way too. 199 | 200 | *Things like [`ember-cli-autoprefixer`](https://github.com/kimroen/ember-cli-autoprefixer) will work out of the box and do not need to be added in as a postcss plugin.* 201 | 202 | ### Getting the generated class name 203 | 204 | You also have access to the generated class name to use in your templates. There is a computed property `styleNamespace` This can be used to pass the class name to things like [`ember-wormhole`](https://github.com/yapplabs/ember-wormhole) or for use in BEM style classnames. 205 | An example of BEM usage would be 206 | 207 | `my-component/template.hbs` 208 | ```handlebars 209 | 212 | 215 | 218 | ``` 219 | `my-component/styles.scss` 220 | ```scss 221 | &__button { 222 | display: inline-block; 223 | border-radius: 3px; 224 | padding: 7px 12px; 225 | border: 1px solid #D5D5D5; 226 | background-image: linear-gradient(#EEE, #DDD); 227 | font: 700 13px/18px Helvetica, arial; 228 | 229 | &--state-success { 230 | color: #FFF; 231 | background: #569E3D linear-gradient(#79D858, #569E3D) repeat-x; 232 | border-color: #4A993E; 233 | } 234 | 235 | &--state-danger { 236 | color: #900; 237 | } 238 | } 239 | ``` 240 | 241 | *`componentCssClassName` will be officially deprecated, then removed in future versions. Will be migrating to the more appropriately named `styleNamespace`* 242 | 243 | #### Using the generated class name in `classNameBindings` 244 | 245 | You can build your own computed properties on top of `styleNamespace`. One use case is using it to build a `classNameBinding`: 246 | 247 | `my-component/component.hbs` 248 | ```js 249 | classNameBindings: ['customBinding'], 250 | stateProperty: false, 251 | customBinding: computed('styleNamespace', 'stateProperty', function() { 252 | if (this.get('stateProperty')) { 253 | return `${this.get('styleNamespace')}--state`; 254 | } else { 255 | return ''; 256 | } 257 | }), 258 | ``` 259 | `my-component/styles.scss` 260 | ```scss 261 | & { 262 | background: blue; 263 | } 264 | &--state { 265 | background: red; 266 | } 267 | ``` 268 | 269 | ### Special Tag-less components 270 | 271 | On the special cases of tag-less components (this functionality is used putting a `tagName: ''` value in the component), the styles are not attached to the DOM, as this addon needs a tag to attach the generated class name. In those special cases, you can use the `styleNamespace`* classname if you want to attach to a another element in the application (or more coherently inside the tag-less component). 272 | 273 | ### Configuration 274 | 275 | You can set the following configuration options in your `config/environment.js` file: 276 | 277 | ```js 278 | ENV['ember-component-css'] = { 279 | option: 'value' 280 | } 281 | ``` 282 | 283 | **namespacing(_enabled_)** 284 | 285 | Defaults to true. Set this option to `false` to disable the namespacing feature of Ember Component CSS. 286 | 287 | ```js 288 | ENV['ember-component-css'] = { 289 | namespacing: false 290 | } 291 | ``` 292 | 293 | This changes the default behavior in two ways: 294 | 295 | 1. The autogenerated component class is no longer added to your component's HTML 296 | 2. Your pod CSS files are no longer namespaced using the autogenerated component class. 297 | 298 | **classicStyleDir** 299 | 300 | Defaults to `component-styles`. Set this to the directory where your classically 301 | structured styles live (within `/app/styles`). For example: 302 | 303 | ```js 304 | ENV['ember-component-css'] = { 305 | classicStyleDir: 'my-styles' 306 | } 307 | ``` 308 | 309 | **excludeFromManifest** 310 | 311 | Defaults to `[]`. Set this option to one or more matcher expression (regular expression, glob string, or function). 312 | Style files matching the expresion(s) will be namespaced but not imported in the `pod-styles` manifest. You will 313 | need to import the matching style files manually in your CSS. This can be useful when you need to control the order 314 | in which specific style files need to be imported. 315 | 316 | Example: 317 | You want to have a separate style file for each media-query breakpoint. You want to be sure that `_style-1366.scss` 318 | will be imported before `_style-960.scss` 319 | 320 | ``` 321 | . 322 | └── my-component/ 323 | ├── _style-1366.scss 324 | ├── _style-960.scss 325 | ├── main.scss 326 | ├── component.js 327 | └── template.hbs 328 | ``` 329 | 330 | ```sass 331 | // main.scss 332 | @import "./_style-1366" 333 | @import "./_style-960" 334 | ``` 335 | 336 | ```js 337 | ENV['ember-component-css'] = { 338 | excludeFromManifest: ['**/_style-*'] 339 | } 340 | ``` 341 | 342 | **patchClassicComponent** 343 | 344 | Set this option to `false` to prevent automatic `Component.reopen()` call which injects 345 | the autogenerated class into component's `classNames` property. 346 | 347 | You would need to use {{this.styleNamespace}} in *all* of your templates instead: 348 | 349 | ```hbs 350 |
351 | Content goes here. 352 |
353 | ``` 354 | 355 | This is required to use `ember-component-css` with Ember 4+ since `Component.reopen()` was removed from Ember.js codebase. 356 | For more details you may refer to [deprecation page](https://deprecations.emberjs.com/v3.x#toc_ember-component-reopen). 357 | 358 | 359 | ### [The announcement from EmberConf 2015](https://youtu.be/T1zxaEKeq3E) 360 | [![CSS is hard - EmberConf 2015](http://f.cl.ly/items/1a3a3r1C1y0D060D3j3u/EmberConf%202015%20-%20CSS%20Is%20Hard%20-%20YouTube%202015-03-22%2018-33-41.jpg)](https://youtu.be/T1zxaEKeq3E) 361 | -------------------------------------------------------------------------------- /addon/initializers/component-styles.js: -------------------------------------------------------------------------------- 1 | import Ember from "ember"; 2 | import Component from '@ember/component'; 3 | import { computed } from '@ember/object'; 4 | import { alias } from '@ember/object/computed'; 5 | import { getOwner } from '@ember/application'; 6 | 7 | import podNames from 'ember-component-css/pod-names'; 8 | 9 | const { 10 | ComponentLookup, 11 | } = Ember; 12 | 13 | ComponentLookup.reopen({ 14 | componentFor(name, owner) { 15 | owner = owner.hasRegistration ? owner : getOwner(this); 16 | 17 | if (podNames[name] && !owner.hasRegistration(`component:${name}`)) { 18 | owner.register(`component:${name}`, Component); 19 | } 20 | return this._super(...arguments); 21 | }, 22 | }); 23 | 24 | Component.reopen({ 25 | _componentIdentifier: computed({ 26 | get() { 27 | return (this._debugContainerKey || '').replace('component:', ''); 28 | } 29 | }), 30 | 31 | _shouldAddNamespacedClassName: computed({ 32 | get() { 33 | return this.get('tagName') !== '' && this.get('styleNamespace'); 34 | } 35 | }), 36 | 37 | styleNamespace: computed({ 38 | get() { 39 | return podNames[this.get('_componentIdentifier')] || ''; 40 | } 41 | }), 42 | 43 | // componentCssClassName: deprecatingAlias('styleNamespace', { 44 | // id: 'ember-component-css.deprecate-componentCssClassName', 45 | // until: '0.7.0', 46 | // }), 47 | 48 | componentCssClassName: alias('styleNamespace'), 49 | 50 | init() { 51 | this._super(...arguments); 52 | 53 | if (this.get('_shouldAddNamespacedClassName')) { 54 | this.classNames = this.classNames.concat(this.get('styleNamespace')); 55 | } 56 | }, 57 | }); 58 | 59 | export function initialize() {} 60 | 61 | export default { 62 | initialize 63 | }; 64 | -------------------------------------------------------------------------------- /addon/initializers/route-styles.js: -------------------------------------------------------------------------------- 1 | import Router from '@ember/routing/router'; 2 | import { getOwner } from '@ember/application'; 3 | import initRouteStyles from '../utils/init-route-styles'; 4 | 5 | // This file is removed from the build in Ember 3.6+ 6 | Router.reopen({ 7 | didTransition(routes) { 8 | this._super(...arguments); 9 | initRouteStyles(getOwner(this), routes.map(route => route.name)); 10 | }, 11 | 12 | intermediateTransitionTo() { 13 | this._super(...arguments); 14 | const routes = this._routerMicrolib.currentHandlerInfos; 15 | const routeNames = routes.map(route => route._handler.routeName.replace(/_loading$/, '-loading')) 16 | 17 | initRouteStyles(getOwner(this), routeNames); 18 | }, 19 | 20 | }); 21 | 22 | export function initialize() {} 23 | 24 | export default { 25 | initialize 26 | }; 27 | -------------------------------------------------------------------------------- /addon/instance-initializers/route-styles.js: -------------------------------------------------------------------------------- 1 | import initRouteStyles from '../utils/init-route-styles'; 2 | 3 | // This file is removed from the build in Ember < 3.6 4 | export function initialize(appInstance) { 5 | let router = appInstance.lookup('service:router'); 6 | router.on('routeDidChange', function({ to }) { 7 | if (likeRouteInfo(to)) { 8 | initRouteStyles(appInstance, nestedRouteNames(to)); 9 | } 10 | }); 11 | 12 | router.on('routeWillChange', function({ to, isActive }) { 13 | if (likeRouteInfo(to)) { 14 | if (/_loading$/.test(to.name) && isActive) { 15 | const routeNames = nestedRouteNames(to) 16 | // loading route names are set with an _loading even though 17 | // their path is -loading 18 | .map(name => name.replace(/_loading$/, '-loading')); 19 | initRouteStyles(appInstance, routeNames); 20 | } 21 | } 22 | }); 23 | } 24 | 25 | function nestedRouteNames({ name, parent }, routeNames = []) { 26 | routeNames.push(name); 27 | if (parent) { 28 | return nestedRouteNames(parent, routeNames); 29 | } 30 | return routeNames; 31 | } 32 | 33 | function likeRouteInfo(info) { 34 | return info && typeof info === 'object' && info.hasOwnProperty('name'); 35 | } 36 | 37 | export default { 38 | initialize 39 | }; 40 | -------------------------------------------------------------------------------- /addon/mixins/style-namespacing-extras.js: -------------------------------------------------------------------------------- 1 | import Mixin from '@ember/object/mixin'; 2 | 3 | export default Mixin.create({}); 4 | -------------------------------------------------------------------------------- /addon/pod-names.js: -------------------------------------------------------------------------------- 1 | export default {}; 2 | -------------------------------------------------------------------------------- /addon/utils/init-route-styles.js: -------------------------------------------------------------------------------- 1 | import podNames from 'ember-component-css/pod-names'; 2 | 3 | export default function initRouteStyles(owner, routeNames) { 4 | const classes = []; 5 | for (let i = 0; i < routeNames.length; i++) { 6 | const routeName = routeNames[i]; 7 | const styleNamespace = podNames[routeName.replace(/\./g, '/')]; 8 | 9 | if (styleNamespace) { 10 | classes.push(styleNamespace); 11 | 12 | const controller = owner.lookup(`controller:${routeName}`); 13 | if (controller) { 14 | controller.set('styleNamespace', styleNamespace); 15 | } 16 | } 17 | } 18 | 19 | let controller = owner 20 | .lookup('controller:application'); 21 | 22 | if (controller) { 23 | controller.set('routeStyleNamespaceClassSet', classes.join(' ')); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/initializers/component-styles.js: -------------------------------------------------------------------------------- 1 | export { default, initialize } from 'ember-component-css/initializers/component-styles'; 2 | 3 | import Ember from 'ember'; 4 | 5 | import StyleNamespacingExtras from '../mixins/style-namespacing-extras'; 6 | 7 | // eslint-disable-next-line ember/new-module-imports 8 | Ember.Component.reopen(StyleNamespacingExtras); 9 | -------------------------------------------------------------------------------- /app/initializers/route-styles.js: -------------------------------------------------------------------------------- 1 | // This file is removed from the build in Ember 3.6+ 2 | export { default, initialize } from 'ember-component-css/initializers/route-styles'; 3 | -------------------------------------------------------------------------------- /app/instance-initializers/route-styles.js: -------------------------------------------------------------------------------- 1 | // This file is removed from the build in Ember < 3.6 2 | export { default, initialize } from 'ember-component-css/instance-initializers/route-styles'; 3 | -------------------------------------------------------------------------------- /app/mixins/style-namespacing-extras.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-component-css/mixins/style-namespacing-extras'; 2 | -------------------------------------------------------------------------------- /bin/install-test-addons.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 'use strict'; 3 | 4 | const fs = require('fs-extra'); 5 | 6 | fs.removeSync('node_modules/test-addon'); 7 | fs.symlinkSync('../tests/dummy/lib/test-addon', 'node_modules/test-addon'); 8 | 9 | fs.removeSync('node_modules/second-test-addon'); 10 | fs.symlinkSync('../tests/dummy/lib/second-test-addon', 'node_modules/second-test-addon'); 11 | 12 | fs.removeSync('node_modules/no-style-files-yet'); 13 | fs.symlinkSync('../tests/dummy/lib/no-style-files-yet', 'node_modules/no-style-files-yet'); 14 | -------------------------------------------------------------------------------- /config/ember-try.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const getChannelURL = require('ember-source-channel-url'); 4 | 5 | module.exports = function() { 6 | return Promise.all([ 7 | getChannelURL('release'), 8 | getChannelURL('beta'), 9 | getChannelURL('canary') 10 | ]).then((urls) => { 11 | return { 12 | useYarn: true, 13 | scenarios: [ 14 | { 15 | name: 'ember-lts-2.16', 16 | env: { 17 | EMBER_OPTIONAL_FEATURES: JSON.stringify({ 'jquery-integration': true }) 18 | }, 19 | npm: { 20 | devDependencies: { 21 | '@ember/jquery': '^0.5.1', 22 | 'ember-source': '~2.16.0' 23 | } 24 | } 25 | }, 26 | { 27 | name: 'ember-lts-2.18', 28 | env: { 29 | EMBER_OPTIONAL_FEATURES: JSON.stringify({ 'jquery-integration': true }) 30 | }, 31 | npm: { 32 | devDependencies: { 33 | '@ember/jquery': '^0.5.1', 34 | 'ember-source': '~2.18.0' 35 | } 36 | } 37 | }, 38 | { 39 | name: 'ember-release', 40 | npm: { 41 | devDependencies: { 42 | 'ember-source': urls[0] 43 | } 44 | } 45 | }, 46 | { 47 | name: 'ember-beta', 48 | npm: { 49 | devDependencies: { 50 | 'ember-source': urls[1] 51 | } 52 | } 53 | }, 54 | { 55 | name: 'ember-canary', 56 | npm: { 57 | devDependencies: { 58 | 'ember-source': urls[2] 59 | } 60 | } 61 | }, 62 | { 63 | name: 'ember-default-with-jquery', 64 | env: { 65 | EMBER_OPTIONAL_FEATURES: JSON.stringify({ 66 | 'jquery-integration': true 67 | }) 68 | }, 69 | npm: { 70 | devDependencies: { 71 | '@ember/jquery': '^0.5.1' 72 | } 73 | } 74 | } 75 | ] 76 | }; 77 | }); 78 | }; 79 | -------------------------------------------------------------------------------- /config/environment.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(/* environment, appConfig */) { 4 | return { }; 5 | }; 6 | -------------------------------------------------------------------------------- /ember-cli-build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); 4 | 5 | module.exports = function(defaults) { 6 | let app = new EmberAddon(defaults, { 7 | "ember-cli-babel": { 8 | includePolyfill: true 9 | } 10 | }); 11 | 12 | /* 13 | This build file specifies the options for the dummy test app of this 14 | addon, located in `/tests/dummy` 15 | This build file does *not* influence how the addon or the app using it 16 | behave. You most likely want to be modifying `./index.js` or app's build file 17 | */ 18 | 19 | return app.toTree(); 20 | }; 21 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Funnel = require('broccoli-funnel'); 4 | var Merge = require('broccoli-merge-trees'); 5 | var ProcessStyles = require('./lib/pod-style.js'); 6 | var ExtractNames = require('./lib/pod-names.js'); 7 | var StyleManifest = require('broccoli-style-manifest'); 8 | var Replace = require('broccoli-replace'); 9 | let VersionChecker = require("ember-cli-version-checker"); 10 | 11 | module.exports = { 12 | 13 | _getStyleFunnel: function() { 14 | return new Merge([this._getPodStyleFunnel(), this._getClassicStyleFunnel()], { 15 | annotation: 'Merge (ember-component-css merge pod and classic styles)' 16 | }); 17 | }, 18 | 19 | _getPodStyleFunnel: function() { 20 | return new Funnel(this.projectRoot, { 21 | srcDir: this._podDirectory(), 22 | exclude: ['styles/**/*'], 23 | include: ['**/*.{' + this.allowedStyleExtensions + ',}'], 24 | allowEmpty: true, 25 | annotation: 'Funnel (ember-component-css grab files)' 26 | }); 27 | }, 28 | 29 | _getClassicStyleFunnel: function() { 30 | return new Funnel(this.projectRoot, { 31 | include: ['styles/' + this.classicStyleDir + '/**/*.{' + this.allowedStyleExtensions + ',}'], 32 | allowEmpty: true, 33 | annotation: 'Funnel (ember-component-css grab classic files)' 34 | }); 35 | }, 36 | 37 | _podDirectory: function() { 38 | return this.appConfig.podModulePrefix && !this._isAddon() ? this.appConfig.podModulePrefix.replace(this.appConfig.modulePrefix, '') : ''; 39 | }, 40 | 41 | _namespacingIsEnabled: function() { 42 | return this.addonConfig.namespacing !== false; 43 | }, 44 | 45 | _isAddon: function() { 46 | return Boolean(this.parent.parent); 47 | }, 48 | 49 | _allPodStyles: [], 50 | 51 | _projectRoot: function(trees) { 52 | var projectRoot; 53 | if (this._isAddon()) { 54 | projectRoot = this.parent.root + '/addon'; 55 | } else if (trees && trees.app) { 56 | projectRoot = trees.app; 57 | } else { 58 | projectRoot = this.parent.root + '/app'; 59 | } 60 | 61 | return projectRoot; 62 | }, 63 | 64 | _getHostApp: function() { 65 | if (!this._findHost) { 66 | this._findHost = function findHostShim() { 67 | let current = this; 68 | let app; 69 | do { 70 | app = current.app || app; 71 | } while (current.parent.parent && (current = current.parent)); 72 | return app; 73 | }; 74 | } 75 | 76 | return this._findHost(); 77 | }, 78 | 79 | _getEnvironment: function() { 80 | return this._getHostApp().env; 81 | }, 82 | 83 | included: function(app) { 84 | this._super.included.apply(this, arguments); 85 | 86 | this.projectRoot = this._projectRoot(app.trees); 87 | 88 | if (this._isAddon()) { 89 | this.parent.treeForMethods['addon-styles'] = 'treeForParentAddonStyles'; 90 | this.parent.treeForParentAddonStyles = this.treeForParentAddonStyles.bind(this); 91 | } 92 | 93 | var hostapp = this._getHostApp(); 94 | if (!hostapp._allPodStyles) { 95 | hostapp._allPodStyles = []; 96 | } 97 | this._allPodStyles = hostapp._allPodStyles; 98 | this.appConfig = app.project.config(this._getEnvironment()); 99 | this.addonConfig = this.appConfig['ember-component-css'] || {}; 100 | this.classicStyleDir = this.addonConfig.classicStyleDir || 'component-styles'; 101 | this.terseClassNames = Boolean(this.addonConfig.terseClassNames); 102 | this.allowedStyleExtensions = app.registry.extensionsForType('css').filter(Boolean); 103 | }, 104 | 105 | config: function(enviroment) { 106 | var config = { 107 | "ember-component-css": { 108 | terseClassNames: false, 109 | }, 110 | }; 111 | if (enviroment === 'production') { 112 | config["ember-component-css"].terseClassNames = true; 113 | } 114 | return config; 115 | }, 116 | 117 | treeForAddon: function(tree) { 118 | if (this._namespacingIsEnabled()) { 119 | var allPodStyles = new Merge(this._allPodStyles, { 120 | overwrite: true, // there are times (specifically with ember engines) where we run over the tree for twice. Should revist and find a way to prevent that in the future. 121 | annotation: 'Merge (ember-component-css merge all process styles for a complete list of styles)' 122 | }); 123 | 124 | var podNames = new ExtractNames(allPodStyles, { 125 | classicStyleDir: this.classicStyleDir, 126 | terseClassNames: this.terseClassNames, 127 | annotation: 'Walk (ember-component-css extract class names from style paths)' 128 | }); 129 | 130 | tree = new Merge([tree, podNames], { 131 | overwrite: true, 132 | annotation: 'Merge (ember-component-css merge names with addon tree)' 133 | }); 134 | } 135 | 136 | let checker = new VersionChecker(this); 137 | let ember = checker.for(`ember-source`); 138 | let superTree = this._super.treeForAddon.call(this, tree); 139 | 140 | // Allow to opt-out from automatic Component.reopen() 141 | if (this.addonConfig.patchClassicComponent === false) { 142 | superTree = new Funnel(superTree, { 143 | exclude: [ 144 | 'ember-component-css/initializers/component-styles.js' 145 | ], 146 | annotation: 147 | "Funnel (ember-component-css exclude addon/initializers/component-styles.js per config)" 148 | }); 149 | } 150 | 151 | if (ember.isAbove('3.6.0')) { 152 | return new Funnel(superTree, { 153 | exclude: ['ember-component-css/initializers/route-styles.js'], 154 | annotation: 155 | "Funnel (ember-component-css exclude addon/initializers/route-styles.js in 3.6+)" 156 | }); 157 | } else { 158 | return new Funnel(superTree, { 159 | exclude: ["ember-component-css/instance-initializers/route-styles.js"], 160 | annotation: 161 | "Funnel (ember-component-css exclude addon/instance-initializers/route-styles.js in < 3.6)" 162 | }); 163 | } 164 | }, 165 | 166 | treeForApp: function(tree) { 167 | // Allow to opt-out from automatic Component.reopen() 168 | if (this.addonConfig.patchClassicComponent === false) { 169 | tree = new Funnel(tree, { 170 | exclude: [ 171 | "initializers/component-styles.js" 172 | ], 173 | annotation: 174 | "Funnel (ember-component-css exclude app/initializers/component-styles.js per config)" 175 | }); 176 | } 177 | 178 | let checker = new VersionChecker(this); 179 | let ember = checker.for(`ember-source`); 180 | if (ember.isAbove('3.6.0')) { 181 | return new Funnel(tree, { 182 | exclude: ["initializers/route-styles.js"], 183 | annotation: 184 | "Funnel (ember-component-css exclude app/initializers/route-styles.js in 3.6+)" 185 | }); 186 | } else { 187 | return new Funnel(tree, { 188 | exclude: ["instance-initializers/route-styles.js"], 189 | annotation: 190 | "Funnel (ember-component-css exclude app/instance-initializers/route-styles.js in < 3.6)" 191 | }); 192 | } 193 | }, 194 | 195 | treeForParentAddonStyles: function(tree) { 196 | let defaultTree = tree; 197 | 198 | if (this.parent.treeForAddonStyles) { 199 | defaultTree = this.parent.treeForAddonStyles.apply(this.parent, arguments); 200 | } 201 | 202 | return this.processComponentStyles(defaultTree); 203 | }, 204 | 205 | treeForStyles: function(tree) { 206 | if (!this._isAddon()) { 207 | tree = this.processComponentStyles(tree); 208 | } 209 | return this._super.treeForStyles.call(this, tree); 210 | }, 211 | 212 | processComponentStyles: function(tree) { 213 | var podStyles = this._getStyleFunnel(); 214 | this._allPodStyles.push(podStyles); 215 | 216 | if (this._namespacingIsEnabled()) { 217 | podStyles = new ProcessStyles(podStyles, { 218 | extensions: this.allowedStyleExtensions, 219 | classicStyleDir: this.classicStyleDir, 220 | terseClassNames: this.terseClassNames, 221 | annotation: 'Filter (ember-component-css process :--component with class names)' 222 | }); 223 | } 224 | 225 | var podStylesWithoutExcluded = new Funnel(podStyles, { 226 | exclude: this.addonConfig.excludeFromManifest || [], 227 | annotation: 'Funnel (ember-component-css exclude style files from manifest)' 228 | }); 229 | 230 | var styleManifest = new StyleManifest(podStylesWithoutExcluded, { 231 | outputFileNameWithoutExtension: 'pod-styles', 232 | annotation: 'StyleManifest (ember-component-css combining all style files that there are extensions for)' 233 | }); 234 | 235 | // this is due to sass spcifically not allowing for ANY semicolons. 236 | styleManifest = new Replace(styleManifest, { 237 | files: ['**/*.sass'], 238 | patterns: [{ 239 | match: /;/g, 240 | replacement: '', 241 | }], 242 | }); 243 | 244 | tree = new Merge([podStyles, styleManifest, tree].filter(Boolean), { 245 | annotation: 'Merge (ember-component-css merge namespacedStyles with style manifest)' 246 | }); 247 | 248 | return tree; 249 | }, 250 | 251 | name: require('./package').name 252 | }; 253 | -------------------------------------------------------------------------------- /lib/component-names.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 'use strict'; 3 | 4 | var md5 = require('md5'); 5 | 6 | module.exports = { 7 | path: function(actualPath, classicStyleDir) { 8 | var terminator = '/'; 9 | var pathSegementToRemove = /^components\//; 10 | 11 | if (actualPath.includes(classicStyleDir)) { 12 | terminator = '.'; 13 | pathSegementToRemove = 'styles/' + classicStyleDir + '/'; 14 | } 15 | 16 | return actualPath.substr(0, actualPath.lastIndexOf(terminator)).replace(pathSegementToRemove, ''); 17 | }, 18 | 19 | class: function(modifiedPath, classicStyleDir, terseClassNames) { 20 | var seperator = '__'; 21 | var componentPath = this.path(modifiedPath, classicStyleDir); 22 | var className = seperator + md5(componentPath).slice(-5); 23 | 24 | if (!terseClassNames) { 25 | className = seperator + componentPath.replace(/\//g, seperator) + className; 26 | } 27 | 28 | return className; 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /lib/pod-names.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 'use strict'; 3 | 4 | var Plugin = require('broccoli-plugin'); 5 | var walkSync = require('walk-sync'); 6 | var fs = require('fs'); 7 | var FSTree = require('fs-tree-diff'); 8 | var Promise = require('rsvp').Promise; 9 | var path = require('path'); 10 | var componentNames = require('./component-names.js'); 11 | 12 | class PodNames extends Plugin { 13 | constructor(inputNode, options = {}) { 14 | super([inputNode], { 15 | annotation: options.annotation, 16 | persistentOutput: true 17 | }); 18 | 19 | this.currentTree = new FSTree(); 20 | this.podNameJson = {}; 21 | this.classicStyleDir = options.classicStyleDir; 22 | this.terseClassNames = options.terseClassNames; 23 | } 24 | 25 | build() { 26 | var srcDir = this.inputPaths[0]; 27 | 28 | var entries = walkSync.entries(srcDir); 29 | var nextTree = FSTree.fromEntries(entries, { sortAndExpand: true }); 30 | var currentTree = this.currentTree; 31 | 32 | this.currentTree = nextTree; 33 | var patches = currentTree.calculatePatch(nextTree); 34 | 35 | return Promise.resolve().then(this.writePodStyleName.bind(this, patches)); 36 | } 37 | 38 | writePodStyleName(patches) { 39 | for (var i = 0; i < patches.length; i++) { 40 | switch (patches[i][0]) { 41 | case 'create': 42 | this.addClass(patches[i][1]); 43 | break; 44 | case 'unlink': 45 | this.removeClass(patches[i][1]); 46 | break; 47 | } 48 | } 49 | 50 | var currentPodNames = {}; 51 | var outputFile = path.join(this.outputPath, 'pod-names.js'); 52 | if (fs.existsSync(outputFile)) { 53 | var contents = fs.readFileSync(outputFile).toString(); 54 | currentPodNames = JSON.parse(contents.substr(contents.indexOf('{'))); 55 | } 56 | 57 | var newPodNames = Object.assign(currentPodNames, this.podNameJson); 58 | var output = 'export default ' + JSON.stringify(newPodNames); 59 | return fs.writeFileSync(path.join(this.outputPath, 'pod-names.js'), output); 60 | } 61 | 62 | addClass(stylePath) { 63 | var componentPath = componentNames.path(stylePath, this.classicStyleDir), 64 | componentClass = componentNames.class(stylePath, this.classicStyleDir, this.terseClassNames); 65 | this.podNameJson[componentPath] = componentClass; 66 | } 67 | 68 | removeClass(stylePath) { 69 | var componentPath = componentNames.path(stylePath, this.classicStyleDir); 70 | delete this.podNameJson[componentPath]; 71 | } 72 | } 73 | 74 | module.exports = PodNames; 75 | -------------------------------------------------------------------------------- /lib/pod-style.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 'use strict'; 3 | 4 | var Filter = require('broccoli-persistent-filter'); 5 | var componentNames = require('./component-names.js'); 6 | var processStratagies = require('./preprocess-class-names'); 7 | var path = require('path'); 8 | 9 | class PodStyles extends Filter { 10 | constructor(inputTree, options) { 11 | super(inputTree, { 12 | annotation: options.annotation 13 | }); 14 | this.extensions = options.extensions; 15 | this.classicStyleDir = options.classicStyleDir; 16 | this.terseClassNames = options.terseClassNames; 17 | } 18 | 19 | processString(contents, stylePath) { 20 | var extension = path.extname(stylePath), 21 | className = componentNames.class(stylePath, this.classicStyleDir, this.terseClassNames), 22 | strategy = 'default'; 23 | 24 | switch (extension) { 25 | case '.styl': 26 | case '.sass': 27 | strategy = 'indentation'; 28 | break; 29 | case '.less': 30 | case '.scss': 31 | strategy = 'syntax'; 32 | break; 33 | } 34 | 35 | return processStratagies[strategy](contents, className, extension); 36 | } 37 | } 38 | 39 | module.exports = PodStyles; 40 | -------------------------------------------------------------------------------- /lib/preprocess-class-names.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 'use strict'; 3 | 4 | var postcss = require('postcss'); 5 | var postcssSelectorNamespace = require('postcss-selector-namespace') 6 | var os = require('os'); 7 | var supportedExtensions = { 8 | ".scss": require('postcss-scss'), 9 | ".less": require('postcss-less') 10 | }; 11 | 12 | function namespaceSelectors(className) { 13 | return postcssSelectorNamespace({ 14 | selfSelector: /&|:--component/, 15 | namespace: '.' + className, 16 | ignoreRoot: false 17 | }); 18 | } 19 | 20 | module.exports = { 21 | indentation: function(contents, className) { 22 | contents = contents.replace(/:--component/g, '&'); 23 | contents = '.' + className + os.EOL + contents; 24 | 25 | // Indent styles for scoping and make sure it ends with a 26 | // newline that is not indented 27 | return contents.replace(new RegExp(os.EOL, 'g'), os.EOL + ' ') + os.EOL; 28 | }, 29 | 30 | wrap: function(contents, className) { 31 | // Replace instances of :--component with '&' 32 | contents = contents.replace(/:--component/g, '&'); 33 | 34 | // Wrap the styles inside the generated class 35 | return '.' + className + '{' + contents + '}'; 36 | }, 37 | 38 | syntax: function(contents, className, extension) { 39 | return postcss().use(namespaceSelectors(className)) 40 | .process(contents, { 41 | syntax: supportedExtensions[extension] 42 | }).css; 43 | }, 44 | 45 | default: function(contents, className) { 46 | return postcss().use(namespaceSelectors(className)).process(contents).css; 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ember-component-css", 3 | "version": "0.8.1", 4 | "description": "An Ember CLI addon which allows you to specify styles for individual components", 5 | "keywords": [ 6 | "ember-addon" 7 | ], 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/ebryn/ember-component-css.git" 11 | }, 12 | "license": "MIT", 13 | "author": "Erik Bryn", 14 | "directories": { 15 | "doc": "doc", 16 | "test": "tests" 17 | }, 18 | "scripts": { 19 | "prepublish": "node ./bin/install-test-addons.js", 20 | "release": "standard-version", 21 | "build": "ember build", 22 | "lint:hbs": "ember-template-lint .", 23 | "lint:js": "eslint .", 24 | "start": "ember serve", 25 | "test": "ember test", 26 | "test:all": "ember try:each" 27 | }, 28 | "dependencies": { 29 | "broccoli-funnel": "^3.0.8", 30 | "broccoli-merge-trees": "^4.2.0", 31 | "broccoli-persistent-filter": "^3.1.2", 32 | "broccoli-plugin": "^4.0.7", 33 | "broccoli-replace": "^2.0.2", 34 | "broccoli-style-manifest": "^1.5.2", 35 | "ember-cli-babel": "^7.1.4", 36 | "ember-cli-version-checker": "^5.1.2", 37 | "ember-getowner-polyfill": "^3.0.2", 38 | "fs-tree-diff": "^2.0.1", 39 | "md5": "^2.3.0", 40 | "postcss": "^7.0.6", 41 | "postcss-less": "^3.1.0", 42 | "postcss-scss": "^2.0.0", 43 | "postcss-selector-namespace": "^2.0.0", 44 | "rsvp": "^4.8.5", 45 | "walk-sync": "^3.0.0" 46 | }, 47 | "devDependencies": { 48 | "@ember/optional-features": "^2.0.0", 49 | "broccoli-asset-rev": "^3.0.0", 50 | "ember-cli": "~3.7.1", 51 | "ember-cli-dependency-checker": "^3.0.0", 52 | "ember-cli-eslint": "^5.0.0", 53 | "ember-cli-htmlbars": "^3.0.1", 54 | "ember-cli-htmlbars-inline-precompile": "^2.0.0", 55 | "ember-cli-inject-live-reload": "^2.0.1", 56 | "ember-cli-sri": "^2.1.1", 57 | "ember-cli-styles-preprocessor": "^0.5.5", 58 | "ember-cli-template-lint": "^1.0.0-beta.1", 59 | "ember-cli-uglify": "^2.1.0", 60 | "ember-disable-prototype-extensions": "^1.1.3", 61 | "ember-export-application-global": "^2.0.0", 62 | "ember-load-initializers": "^2.0.0", 63 | "ember-maybe-import-regenerator": "^0.1.6", 64 | "ember-qunit": "^4.1.2", 65 | "ember-resolver": "^5.0.1", 66 | "ember-source": "~3.10.2", 67 | "ember-source-channel-url": "^1.1.0", 68 | "ember-try": "^1.1.0", 69 | "eslint-plugin-ember": "^6.0.1", 70 | "eslint-plugin-node": "^8.0.0", 71 | "fs-extra": "^7.0.1", 72 | "loader.js": "^4.7.0", 73 | "no-style-files-yet": "file:./tests/dummy/lib/no-style-files-yet", 74 | "qunit-dom": "^0.8.0", 75 | "second-test-addon": "file:./tests/dummy/lib/second-test-addon", 76 | "standard-version": "^4.4.0", 77 | "test-addon": "file:./tests/dummy/lib/test-addon" 78 | }, 79 | "engines": { 80 | "node": "12.* || 14.* || >= 16" 81 | }, 82 | "ember-addon": { 83 | "before": [ 84 | "ember-cli-styles-preprocessor", 85 | "ember-cli-less", 86 | "ember-cli-sass", 87 | "ember-cli-stylus", 88 | "ember-cli-postcss" 89 | ], 90 | "configPath": "tests/dummy/config" 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /testem.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | test_page: 'tests/index.html?hidepassed', 3 | disable_watching: true, 4 | launch_in_ci: [ 5 | 'Chrome' 6 | ], 7 | launch_in_dev: [ 8 | 'Chrome' 9 | ], 10 | browser_args: { 11 | Chrome: { 12 | ci: [ 13 | // --no-sandbox is needed when running Chrome inside a container 14 | process.env.CI ? '--no-sandbox' : null, 15 | '--headless', 16 | '--disable-gpu', 17 | '--disable-dev-shm-usage', 18 | '--disable-software-rasterizer', 19 | '--mute-audio', 20 | '--remote-debugging-port=0', 21 | '--window-size=1440,900' 22 | ].filter(Boolean) 23 | } 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /tests/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | embertest: true 4 | } 5 | }; 6 | -------------------------------------------------------------------------------- /tests/acceptance/aborted-state-test.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('Acceptance | aborted state'); 5 | 6 | test('when aborting it should finish the transition and not error', function(assert) { 7 | visit('/aborted-state'); 8 | 9 | 10 | andThen(function() { 11 | assert.equal(currentURL(), '/template-style-only'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /tests/acceptance/addon-less-test.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | const TYPE = 'less'; 5 | const PATH = `/addon/${TYPE}`; 6 | 7 | moduleForAcceptance(`Acceptance | Addon for ${TYPE}`); 8 | 9 | test('base rule followed', function(assert) { 10 | visit(PATH); 11 | 12 | andThen(function() { 13 | assert.equal(find('.base').css('color'), 'rgb(1, 0, 1)'); 14 | }); 15 | }); 16 | 17 | test('nested rule followed', function(assert) { 18 | visit(PATH); 19 | 20 | andThen(function() { 21 | assert.equal(find('.nested').css('color'), 'rgb(1, 0, 2)'); 22 | }); 23 | }); 24 | 25 | test('non class nested rule followed', function(assert) { 26 | visit(PATH); 27 | 28 | andThen(function() { 29 | assert.equal(find('span span span').css('color'), 'rgb(1, 0, 3)'); 30 | }); 31 | }); 32 | 33 | test('BEM rule followed', function(assert) { 34 | visit(PATH); 35 | 36 | andThen(function() { 37 | assert.equal(find('[class$=__element]').css('color'), 'rgb(1, 0, 4)'); 38 | }); 39 | }); 40 | 41 | test('BEM variant rule followed', function(assert) { 42 | visit(PATH); 43 | 44 | andThen(function() { 45 | assert.equal(find('[class$=__element--variant]').css('color'), 'rgb(1, 0, 5)'); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /tests/acceptance/addon-scss-test.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | const TYPE = 'scss'; 5 | const PATH = `/addon/${TYPE}`; 6 | 7 | moduleForAcceptance(`Acceptance | Addon for ${TYPE}`); 8 | 9 | test('base rule followed', function(assert) { 10 | visit(PATH); 11 | 12 | andThen(function() { 13 | assert.equal(find('.base').css('color'), 'rgb(1, 0, 1)'); 14 | }); 15 | }); 16 | 17 | test('nested rule followed', function(assert) { 18 | visit(PATH); 19 | 20 | andThen(function() { 21 | assert.equal(find('.nested').css('color'), 'rgb(1, 0, 2)'); 22 | }); 23 | }); 24 | 25 | test('non class nested rule followed', function(assert) { 26 | visit(PATH); 27 | 28 | andThen(function() { 29 | assert.equal(find('span span span').css('color'), 'rgb(1, 0, 3)'); 30 | }); 31 | }); 32 | 33 | test('BEM rule followed', function(assert) { 34 | visit(PATH); 35 | 36 | andThen(function() { 37 | assert.equal(find('[class$=__element]').css('color'), 'rgb(1, 0, 4)'); 38 | }); 39 | }); 40 | 41 | test('BEM variant rule followed', function(assert) { 42 | visit(PATH); 43 | 44 | andThen(function() { 45 | assert.equal(find('[class$=__element--variant]').css('color'), 'rgb(1, 0, 5)'); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /tests/acceptance/classic-structure-test.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('Acceptance | classic structure'); 5 | 6 | test('should be able to use classic structure style', function(assert) { 7 | visit('/classic-structure'); 8 | 9 | andThen(function() { 10 | assert.equal(find('.classic-structure').css('color'), 'rgb(0, 0, 1)'); 11 | }); 12 | }); 13 | 14 | test('should be able to use classic structure style nested', function(assert) { 15 | visit('/classic-structure-nested'); 16 | 17 | andThen(function() { 18 | assert.equal(find('.classic-structure-nested').css('color'), 'rgb(0, 0, 1)'); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /tests/acceptance/css-test.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | const TYPE = 'css'; 5 | 6 | moduleForAcceptance(`Acceptance | ${TYPE}`); 7 | 8 | test('base rule followed', function(assert) { 9 | visit(`/${TYPE}`); 10 | 11 | andThen(function() { 12 | assert.equal(find('.base').css('color'), 'rgb(0, 0, 1)'); 13 | }); 14 | }); 15 | 16 | test('nested rule followed', function(assert) { 17 | visit(`/${TYPE}`); 18 | 19 | andThen(function() { 20 | assert.equal(find('.nested').css('color'), 'rgb(0, 0, 2)'); 21 | }); 22 | }); 23 | 24 | test('non class nested rule followed', function(assert) { 25 | visit(`/${TYPE}`); 26 | 27 | andThen(function() { 28 | assert.equal(find('span span span').css('color'), 'rgb(0, 0, 3)'); 29 | }); 30 | }); 31 | 32 | test('BEM rule followed', function(assert) { 33 | visit(`/${TYPE}`); 34 | 35 | andThen(function() { 36 | assert.equal(find('[class$=__element]').css('color'), 'rgb(0, 0, 4)'); 37 | }); 38 | }); 39 | 40 | test('BEM variant rule followed', function(assert) { 41 | visit(`/${TYPE}`); 42 | 43 | andThen(function() { 44 | assert.equal(find('[class$=__element--variant]').css('color'), 'rgb(0, 0, 5)'); 45 | }); 46 | }); 47 | 48 | test('route style followed', function(assert) { 49 | visit(`/${TYPE}`); 50 | 51 | andThen(function() { 52 | assert.equal(find(`div[class^="__${TYPE}"]`).css('color'), 'rgb(0, 1, 0)'); 53 | }); 54 | }); 55 | 56 | test('nested route style followed', function(assert) { 57 | visit(`/${TYPE}/nested`); 58 | 59 | andThen(function() { 60 | assert.equal(find(`div[class*="__${TYPE}__nested"]`).css('color'), 'rgb(0, 2, 0)'); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /tests/acceptance/error-state-test.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance(`Acceptance | error state`); 5 | 6 | test('handled error state does not throw', function(assert) { 7 | visit(`/error-state/handled`); 8 | 9 | andThen(function() { 10 | assert.equal(currentURL(), '/error-state'); 11 | assert.equal(find('h1').css('color'), 'rgb(0, 0, 14)'); 12 | }) 13 | }); 14 | -------------------------------------------------------------------------------- /tests/acceptance/less-test.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | const TYPE = 'less'; 5 | 6 | moduleForAcceptance(`Acceptance | ${TYPE}`); 7 | 8 | test('base rule followed', function(assert) { 9 | visit(`/${TYPE}`); 10 | 11 | andThen(function() { 12 | assert.equal(find('.base').css('color'), 'rgb(0, 0, 1)'); 13 | }); 14 | }); 15 | 16 | test('nested rule followed', function(assert) { 17 | visit(`/${TYPE}`); 18 | 19 | andThen(function() { 20 | assert.equal(find('.nested').css('color'), 'rgb(0, 0, 2)'); 21 | }); 22 | }); 23 | 24 | test('non class nested rule followed', function(assert) { 25 | visit(`/${TYPE}`); 26 | 27 | andThen(function() { 28 | assert.equal(find('span span span').css('color'), 'rgb(0, 0, 3)'); 29 | }); 30 | }); 31 | 32 | test('BEM rule followed', function(assert) { 33 | visit(`/${TYPE}`); 34 | 35 | andThen(function() { 36 | assert.equal(find('[class$=__element]').css('color'), 'rgb(0, 0, 4)'); 37 | }); 38 | }); 39 | 40 | test('BEM variant rule followed', function(assert) { 41 | visit(`/${TYPE}`); 42 | 43 | andThen(function() { 44 | assert.equal(find('[class$=__element--variant]').css('color'), 'rgb(0, 0, 5)'); 45 | }); 46 | }); 47 | 48 | test('route style followed', function(assert) { 49 | visit(`/${TYPE}`); 50 | 51 | andThen(function() { 52 | assert.equal(find(`div[class^="__${TYPE}"]`).css('color'), 'rgb(0, 1, 0)'); 53 | }); 54 | 55 | andThen(function() { 56 | visit(`/${TYPE}/nested`); 57 | }); 58 | }); 59 | 60 | test('nested route style followed', function(assert) { 61 | visit(`/${TYPE}/nested`); 62 | 63 | andThen(function() { 64 | assert.equal(find(`div[class*="__${TYPE}__nested"]`).css('color'), 'rgb(0, 2, 0)'); 65 | }); 66 | }); 67 | -------------------------------------------------------------------------------- /tests/acceptance/loading-state-test.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | import { scheduleOnce } from '@ember/runloop'; 4 | 5 | moduleForAcceptance(`Acceptance | loading state`); 6 | 7 | test('loading state is styled', function(assert) { 8 | visit(`/loading-state/base`); 9 | 10 | andThen(function() { 11 | click(find('a')); 12 | assert.equal(find('h1').css('color'), 'rgb(0, 0, 14)'); 13 | 14 | scheduleOnce('afterRender', function() { 15 | assert.equal(find('h2').css('color'), 'rgb(1, 0, 13)'); 16 | }); 17 | 18 | }); 19 | 20 | andThen(function() { 21 | assert.equal(find('h3').css('color'), 'rgb(0, 0, 13)'); 22 | }) 23 | }); 24 | -------------------------------------------------------------------------------- /tests/acceptance/no-style-files-yet-test.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('Acceptance | no style files yet'); 5 | 6 | test('should not have to include a style file inorder to build and render', function(assert) { 7 | visit('/no-style-files-yet'); 8 | 9 | andThen(function() { 10 | assert.equal(find('.base').css('color'), 'rgb(0, 0, 0)'); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /tests/acceptance/query-params-test.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance(`Acceptance | query params`); 5 | 6 | test('route style with query params', function(assert) { 7 | visit(`/query-params`); 8 | 9 | andThen(function() { 10 | assert.equal(find(`div[class^="__query-params"]`).css('color'), 'rgb(0, 1, 0)'); 11 | 12 | click('a.foo-bar'); 13 | 14 | andThen(function() { 15 | assert.equal(currentURL(), '/query-params?foo=bar'); 16 | assert.equal(find(`div[class^="__query-params"]`).css('color'), 'rgb(0, 1, 0)'); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /tests/acceptance/sass-test.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | const TYPE = 'sass'; 5 | 6 | moduleForAcceptance(`Acceptance | ${TYPE}`); 7 | 8 | test('base rule followed', function(assert) { 9 | visit(`/${TYPE}`); 10 | 11 | andThen(function() { 12 | assert.equal(find('.base').css('color'), 'rgb(0, 0, 1)'); 13 | }); 14 | }); 15 | 16 | test('nested rule followed', function(assert) { 17 | visit(`/${TYPE}`); 18 | 19 | andThen(function() { 20 | assert.equal(find('.nested').css('color'), 'rgb(0, 0, 2)'); 21 | }); 22 | }); 23 | 24 | test('non class nested rule followed', function(assert) { 25 | visit(`/${TYPE}`); 26 | 27 | andThen(function() { 28 | assert.equal(find('span span span').css('color'), 'rgb(0, 0, 3)'); 29 | }); 30 | }); 31 | 32 | test('BEM rule followed', function(assert) { 33 | visit(`/${TYPE}`); 34 | 35 | andThen(function() { 36 | assert.equal(find('[class$=__element]').css('color'), 'rgb(0, 0, 4)'); 37 | }); 38 | }); 39 | 40 | test('BEM variant rule followed', function(assert) { 41 | visit(`/${TYPE}`); 42 | 43 | andThen(function() { 44 | assert.equal(find('[class$=__element--variant]').css('color'), 'rgb(0, 0, 5)'); 45 | }); 46 | }); 47 | 48 | test('mixin psudo elements do not get scoped', function(assert) { 49 | visit(`/${TYPE}`); 50 | 51 | andThen(function() { 52 | let item = find('[class$=__element--variant]'); 53 | item.addClass('mixin-extra'); 54 | assert.equal(item.css('color'), 'rgb(0, 0, 6)'); 55 | }); 56 | }); 57 | 58 | test('route style followed', function(assert) { 59 | visit(`/${TYPE}`); 60 | 61 | andThen(function() { 62 | assert.equal(find(`div[class^="__${TYPE}"]`).css('color'), 'rgb(0, 1, 0)'); 63 | }); 64 | }); 65 | 66 | test('nested route style followed', function(assert) { 67 | visit(`/${TYPE}/nested`); 68 | 69 | andThen(function() { 70 | assert.equal(find(`div[class*="__${TYPE}__nested"]`).css('color'), 'rgb(0, 2, 0)'); 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /tests/acceptance/scss-test.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | const TYPE = 'scss'; 5 | 6 | moduleForAcceptance(`Acceptance | ${TYPE}`); 7 | 8 | test('base rule followed', function(assert) { 9 | visit(`/${TYPE}`); 10 | 11 | andThen(function() { 12 | assert.equal(find('.base').css('color'), 'rgb(0, 0, 1)'); 13 | }); 14 | }); 15 | 16 | test('nested rule followed', function(assert) { 17 | visit(`/${TYPE}`); 18 | 19 | andThen(function() { 20 | assert.equal(find('.nested').css('color'), 'rgb(0, 0, 2)'); 21 | }); 22 | }); 23 | 24 | test('non class nested rule followed', function(assert) { 25 | visit(`/${TYPE}`); 26 | 27 | andThen(function() { 28 | assert.equal(find('span span span').css('color'), 'rgb(0, 0, 3)'); 29 | }); 30 | }); 31 | 32 | test('BEM rule followed', function(assert) { 33 | visit(`/${TYPE}`); 34 | 35 | andThen(function() { 36 | assert.equal(find('[class$=__element]').css('color'), 'rgb(0, 0, 4)'); 37 | }); 38 | }); 39 | 40 | test('BEM variant rule followed', function(assert) { 41 | visit(`/${TYPE}`); 42 | 43 | andThen(function() { 44 | assert.equal(find('[class$=__element--variant]').css('color'), 'rgb(0, 0, 5)'); 45 | }); 46 | }); 47 | 48 | test('mixin psudo elements do not get scoped', function(assert) { 49 | visit(`/${TYPE}`); 50 | 51 | andThen(function() { 52 | let item = find('[class$=__element--variant]'); 53 | item.addClass('mixin-extra'); 54 | assert.equal(item.css('color'), 'rgb(0, 0, 6)'); 55 | }); 56 | }); 57 | 58 | test('children of root @for rules are namspaced', function(assert) { 59 | visit(`/${TYPE}`); 60 | 61 | andThen(function() { 62 | for (let index of Array(10).keys()) { 63 | let item = find(`[class$=__element--${index}]`); 64 | assert.equal(item.css('color'), `rgb(0, 0, ${index})`); 65 | } 66 | }); 67 | }); 68 | 69 | test('route style followed', function(assert) { 70 | visit(`/${TYPE}`); 71 | 72 | andThen(function() { 73 | assert.equal(find(`div[class^="__${TYPE}"]`).css('color'), 'rgb(0, 1, 0)'); 74 | }); 75 | }); 76 | 77 | test('nested route style followed', function(assert) { 78 | visit(`/${TYPE}/nested`); 79 | 80 | andThen(function() { 81 | assert.equal(find(`div[class*="__${TYPE}__nested"]`).css('color'), 'rgb(0, 2, 0)'); 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /tests/acceptance/styl-test.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | const TYPE = 'styl'; 5 | 6 | moduleForAcceptance(`Acceptance | ${TYPE}`); 7 | 8 | test('base rule followed', function(assert) { 9 | visit(`/${TYPE}`); 10 | 11 | andThen(function() { 12 | assert.equal(find('.base').css('color'), 'rgb(0, 0, 1)'); 13 | }); 14 | }); 15 | 16 | test('nested rule followed', function(assert) { 17 | visit(`/${TYPE}`); 18 | 19 | andThen(function() { 20 | assert.equal(find('.nested').css('color'), 'rgb(0, 0, 2)'); 21 | }); 22 | }); 23 | 24 | test('non class nested rule followed', function(assert) { 25 | visit(`/${TYPE}`); 26 | 27 | andThen(function() { 28 | assert.equal(find('span span span').css('color'), 'rgb(0, 0, 3)'); 29 | }); 30 | }); 31 | 32 | test('BEM rule followed', function(assert) { 33 | visit(`/${TYPE}`); 34 | 35 | andThen(function() { 36 | assert.equal(find('[class$=__element]').css('color'), 'rgb(0, 0, 4)'); 37 | }); 38 | }); 39 | 40 | test('BEM variant rule followed', function(assert) { 41 | visit(`/${TYPE}`); 42 | 43 | andThen(function() { 44 | assert.equal(find('[class$=__element--variant]').css('color'), 'rgb(0, 0, 5)'); 45 | }); 46 | }); 47 | 48 | test('route style followed', function(assert) { 49 | visit(`/${TYPE}`); 50 | 51 | andThen(function() { 52 | assert.equal(find(`div[class^="__${TYPE}"]`).css('color'), 'rgb(0, 1, 0)'); 53 | }); 54 | }); 55 | 56 | test('nested route style followed', function(assert) { 57 | visit(`/${TYPE}/nested`); 58 | 59 | andThen(function() { 60 | assert.equal(find(`div[class*="__${TYPE}__nested"]`).css('color'), 'rgb(0, 2, 0)'); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /tests/acceptance/template-style-only-test.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('Acceptance | template style only'); 5 | 6 | test('should be able to use a pod style with only the style file and a template', function(assert) { 7 | visit('/template-style-only'); 8 | 9 | andThen(function() { 10 | assert.equal(find('.template-only').css('color'), 'rgb(0, 0, 1)'); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /tests/acceptance/unique-component-paths-test.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance(`Acceptance | unique component paths`); 5 | 6 | test('base rule followed', function(assert) { 7 | visit(`/unique-component-paths`); 8 | 9 | andThen(function() { 10 | assert.equal(find('h1').css('color'), 'rgb(0, 0, 14)'); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /tests/dummy/app/aborted-state/route.js: -------------------------------------------------------------------------------- 1 | import Route from '@ember/routing/route'; 2 | 3 | export default Route.extend({ 4 | beforeModel(transition) { 5 | transition.abort(); 6 | this.transitionTo('template-style-only') 7 | return this._super(...arguments); 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /tests/dummy/app/aborted-state/template.hbs: -------------------------------------------------------------------------------- 1 |

you will never see me

2 | -------------------------------------------------------------------------------- /tests/dummy/app/addon/less/template.hbs: -------------------------------------------------------------------------------- 1 | {{second-addon-less}} 2 | -------------------------------------------------------------------------------- /tests/dummy/app/addon/scss/template.hbs: -------------------------------------------------------------------------------- 1 | {{addon-scss}} 2 | -------------------------------------------------------------------------------- /tests/dummy/app/app.js: -------------------------------------------------------------------------------- 1 | import Application from '@ember/application'; 2 | import Resolver from './resolver'; 3 | import loadInitializers from 'ember-load-initializers'; 4 | import config from './config/environment'; 5 | 6 | const App = Application.extend({ 7 | modulePrefix: config.modulePrefix, 8 | podModulePrefix: config.podModulePrefix, 9 | Resolver 10 | }); 11 | 12 | loadInitializers(App, config.modulePrefix); 13 | 14 | export default App; 15 | -------------------------------------------------------------------------------- /tests/dummy/app/components/base-rules/component.js: -------------------------------------------------------------------------------- 1 | import Component from '@ember/component'; 2 | 3 | import layout from './template'; 4 | 5 | export default Component.extend({ 6 | layout 7 | }); 8 | -------------------------------------------------------------------------------- /tests/dummy/app/components/base-rules/template.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | element variant 9 | -------------------------------------------------------------------------------- /tests/dummy/app/components/css/base-rules/component.js: -------------------------------------------------------------------------------- 1 | import BaseRules from 'dummy/components/base-rules/component'; 2 | 3 | export default BaseRules.extend(); 4 | -------------------------------------------------------------------------------- /tests/dummy/app/components/css/base-rules/styles.css: -------------------------------------------------------------------------------- 1 | .base { 2 | color: rgb(0, 0, 1); 3 | } 4 | 5 | .base .nested { 6 | color: rgb(0, 0, 2); 7 | } 8 | 9 | span > span > span { 10 | color: rgb(0, 0, 3); 11 | } 12 | 13 | &__element { 14 | color: rgb(0, 0, 4); 15 | } 16 | 17 | &__element--variant { 18 | color: rgb(0, 0, 5); 19 | } 20 | -------------------------------------------------------------------------------- /tests/dummy/app/components/less/base-rules/component.js: -------------------------------------------------------------------------------- 1 | import BaseRules from 'dummy/components/base-rules/component'; 2 | 3 | export default BaseRules.extend(); 4 | -------------------------------------------------------------------------------- /tests/dummy/app/components/less/base-rules/styles.less: -------------------------------------------------------------------------------- 1 | .base { 2 | color: rgb(0, 0, 1); 3 | 4 | .nested { 5 | color: rgb(0, 0, 2); 6 | } 7 | } 8 | 9 | span { 10 | > span { 11 | > span { 12 | color: rgb(0, 0, 3); 13 | } 14 | } 15 | } 16 | 17 | & { 18 | &__element { 19 | color: rgb(0, 0, 4); 20 | 21 | &--variant { 22 | color: rgb(0, 0, 5); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/dummy/app/components/sass/base-rules/component.js: -------------------------------------------------------------------------------- 1 | import BaseRules from 'dummy/components/base-rules/component'; 2 | 3 | export default BaseRules.extend(); 4 | -------------------------------------------------------------------------------- /tests/dummy/app/components/sass/base-rules/styles.sass: -------------------------------------------------------------------------------- 1 | @mixin mixin() 2 | &.mixin-extra 3 | color: rgb(0, 0, 6) 4 | 5 | .base 6 | color: rgb(0, 0, 1) 7 | 8 | .nested 9 | color: rgb(0, 0, 2) 10 | 11 | span 12 | > span 13 | > span 14 | color: rgb(0, 0, 3) 15 | 16 | & 17 | &__element 18 | color: rgb(0, 0, 4) 19 | 20 | &--variant 21 | color: rgb(0, 0, 5) 22 | @include mixin 23 | -------------------------------------------------------------------------------- /tests/dummy/app/components/scss/base-rules/component.js: -------------------------------------------------------------------------------- 1 | import BaseRules from 'dummy/components/base-rules/component'; 2 | 3 | export default BaseRules.extend(); 4 | -------------------------------------------------------------------------------- /tests/dummy/app/components/scss/base-rules/styles.scss: -------------------------------------------------------------------------------- 1 | @mixin mixin() { 2 | &.mixin-extra { 3 | color: rgb(0, 0, 6); 4 | } 5 | } 6 | 7 | .base { 8 | color: rgb(0, 0, 1); 9 | 10 | .nested { 11 | color: rgb(0, 0, 2); 12 | } 13 | } 14 | 15 | span { 16 | > span { 17 | > span { 18 | color: rgb(0, 0, 3); 19 | } 20 | } 21 | } 22 | 23 | & { 24 | &__element { 25 | color: rgb(0, 0, 4); 26 | 27 | &--variant { 28 | color: rgb(0, 0, 5); 29 | @include mixin; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/dummy/app/components/scss/for-loop/component.js: -------------------------------------------------------------------------------- 1 | import Component from '@ember/component'; 2 | import { computed } from '@ember/object'; 3 | 4 | export default Component.extend({ 5 | items: computed({ 6 | get() { 7 | return [...Array(10).keys()]; 8 | }, 9 | }), 10 | }); 11 | -------------------------------------------------------------------------------- /tests/dummy/app/components/scss/for-loop/styles.scss: -------------------------------------------------------------------------------- 1 | @for $index from 0 through 9 { 2 | &__element--#{$index} { 3 | color: rgb(0, 0, $index); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/dummy/app/components/scss/for-loop/template.hbs: -------------------------------------------------------------------------------- 1 | {{#each items as |item|}} 2 | 3 | {{/each}} 4 | -------------------------------------------------------------------------------- /tests/dummy/app/components/styl/base-rules/component.js: -------------------------------------------------------------------------------- 1 | import BaseRules from 'dummy/components/base-rules/component'; 2 | 3 | export default BaseRules.extend(); 4 | -------------------------------------------------------------------------------- /tests/dummy/app/components/styl/base-rules/styles.styl: -------------------------------------------------------------------------------- 1 | .base 2 | color rgb(0, 0, 1) 3 | 4 | .nested 5 | color rgb(0, 0, 2) 6 | 7 | span 8 | > span 9 | > span 10 | color rgb(0, 0, 3) 11 | 12 | & 13 | &__element 14 | color rgb(0, 0, 4) 15 | 16 | &--variant 17 | color rgb(0, 0, 5) 18 | -------------------------------------------------------------------------------- /tests/dummy/app/components/template-and-style/styles.scss: -------------------------------------------------------------------------------- 1 | .template-only { 2 | color: rgb(0, 0, 1); 3 | } 4 | -------------------------------------------------------------------------------- /tests/dummy/app/components/template-and-style/template.hbs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/dummy/app/css/nested/styles.css: -------------------------------------------------------------------------------- 1 | & { 2 | color: rgb(0, 2, 0); 3 | } 4 | -------------------------------------------------------------------------------- /tests/dummy/app/css/styles.css: -------------------------------------------------------------------------------- 1 | & { 2 | color: rgb(0, 1, 0); 3 | } 4 | -------------------------------------------------------------------------------- /tests/dummy/app/css/template.hbs: -------------------------------------------------------------------------------- 1 | {{css/base-rules}} 2 | -------------------------------------------------------------------------------- /tests/dummy/app/error-state/handled/route.js: -------------------------------------------------------------------------------- 1 | import Route from '@ember/routing/route'; 2 | import { later } from '@ember/runloop'; 3 | import RSVP from 'rsvp'; 4 | 5 | export default Route.extend({ 6 | model() { 7 | return new RSVP.Promise((_resolve, reject) => later(reject)); 8 | }, 9 | 10 | actions: { 11 | error() { 12 | this.transitionTo('error-state'); 13 | } 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /tests/dummy/app/error-state/styles.scss: -------------------------------------------------------------------------------- 1 | h1 { 2 | color: rgb(0, 0, 14); 3 | } 4 | -------------------------------------------------------------------------------- /tests/dummy/app/error-state/template.hbs: -------------------------------------------------------------------------------- 1 |

error-state

2 | -------------------------------------------------------------------------------- /tests/dummy/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dummy 7 | 8 | 9 | 10 | {{content-for "head"}} 11 | 12 | 13 | 14 | 15 | {{content-for "head-footer"}} 16 | 17 | 18 | {{content-for "body"}} 19 | 20 | 21 | 22 | 23 | {{content-for "body-footer"}} 24 | 25 | 26 | -------------------------------------------------------------------------------- /tests/dummy/app/less/nested/styles.less: -------------------------------------------------------------------------------- 1 | & { 2 | color: rgb(0, 2, 0); 3 | } 4 | -------------------------------------------------------------------------------- /tests/dummy/app/less/styles.less: -------------------------------------------------------------------------------- 1 | & { 2 | color: rgb(0, 1, 0); 3 | } 4 | -------------------------------------------------------------------------------- /tests/dummy/app/less/template.hbs: -------------------------------------------------------------------------------- 1 | {{less/base-rules}} 2 | -------------------------------------------------------------------------------- /tests/dummy/app/loading-state/base/styles.scss: -------------------------------------------------------------------------------- 1 | h1 { 2 | color: rgb(0, 0, 14); 3 | } 4 | -------------------------------------------------------------------------------- /tests/dummy/app/loading-state/base/template.hbs: -------------------------------------------------------------------------------- 1 |

base

2 | {{link-to "waiting" "loading-state.waiting"}} 3 | -------------------------------------------------------------------------------- /tests/dummy/app/loading-state/waiting-loading/styles.scss: -------------------------------------------------------------------------------- 1 | h2 { 2 | color: rgb(1, 0, 13); 3 | } 4 | -------------------------------------------------------------------------------- /tests/dummy/app/loading-state/waiting-loading/template.hbs: -------------------------------------------------------------------------------- 1 |

loading

2 | -------------------------------------------------------------------------------- /tests/dummy/app/loading-state/waiting/route.js: -------------------------------------------------------------------------------- 1 | import Route from '@ember/routing/route'; 2 | import { later } from '@ember/runloop'; 3 | import RSVP from 'rsvp'; 4 | 5 | export default Route.extend({ 6 | model() { 7 | return new RSVP.Promise(resolve => later(resolve, 500)); 8 | } 9 | }); 10 | -------------------------------------------------------------------------------- /tests/dummy/app/loading-state/waiting/styles.scss: -------------------------------------------------------------------------------- 1 | h3 { 2 | color: rgb(0, 0, 13); 3 | } 4 | -------------------------------------------------------------------------------- /tests/dummy/app/loading-state/waiting/template.hbs: -------------------------------------------------------------------------------- 1 |

loaded

2 | -------------------------------------------------------------------------------- /tests/dummy/app/no-style-files-yet/template.hbs: -------------------------------------------------------------------------------- 1 | {{no-style}} 2 | -------------------------------------------------------------------------------- /tests/dummy/app/query-params/controller.js: -------------------------------------------------------------------------------- 1 | import Controller from '@ember/controller'; 2 | 3 | export default Controller.extend({ 4 | queryParams: ['foo'] 5 | }); 6 | -------------------------------------------------------------------------------- /tests/dummy/app/query-params/route.js: -------------------------------------------------------------------------------- 1 | import Route from '@ember/routing/route'; 2 | 3 | export default Route.extend({ 4 | queryParams: { 5 | foo: { 6 | refreshModel: true 7 | } 8 | } 9 | }); 10 | -------------------------------------------------------------------------------- /tests/dummy/app/query-params/styles.scss: -------------------------------------------------------------------------------- 1 | & { 2 | color: rgb(0, 1, 0); 3 | } 4 | -------------------------------------------------------------------------------- /tests/dummy/app/query-params/template.hbs: -------------------------------------------------------------------------------- 1 | {{#link-to (query-params foo="bar") class="foo-bar"}} 2 | bar 3 | {{/link-to}} -------------------------------------------------------------------------------- /tests/dummy/app/resolver.js: -------------------------------------------------------------------------------- 1 | import Resolver from 'ember-resolver'; 2 | 3 | export default Resolver; 4 | -------------------------------------------------------------------------------- /tests/dummy/app/router.js: -------------------------------------------------------------------------------- 1 | import EmberRouter from '@ember/routing/router'; 2 | import config from './config/environment'; 3 | 4 | const Router = EmberRouter.extend({ 5 | location: config.locationType, 6 | rootURL: config.rootURL 7 | }); 8 | 9 | Router.map(function() { 10 | this.route('css', function() { 11 | this.route('nested'); 12 | }); 13 | 14 | this.route('scss', function() { 15 | this.route('nested'); 16 | }); 17 | 18 | this.route('sass', function() { 19 | this.route('nested'); 20 | }); 21 | 22 | this.route('styl', function() { 23 | this.route('nested'); 24 | }); 25 | 26 | this.route('less', function() { 27 | this.route('nested'); 28 | }); 29 | 30 | this.route('template-style-only'); 31 | this.route('no-style-files-yet'); 32 | this.route('classic-structure'); 33 | this.route('classic-structure-nested'); 34 | this.route('unique-component-paths'); 35 | this.route('query-params'); 36 | 37 | this.route('addon', function() { 38 | this.route('scss'); 39 | this.route('less'); 40 | }); 41 | 42 | this.route('loading-state', function() { 43 | this.route('base'); 44 | this.route('waiting'); 45 | }); 46 | 47 | this.route('error-state', function() { 48 | this.route('handled'); 49 | }); 50 | 51 | this.route('aborted-state'); 52 | }); 53 | 54 | export default Router; 55 | -------------------------------------------------------------------------------- /tests/dummy/app/sass/nested/styles.sass: -------------------------------------------------------------------------------- 1 | & 2 | color: rgb(0, 2, 0) 3 | -------------------------------------------------------------------------------- /tests/dummy/app/sass/styles.sass: -------------------------------------------------------------------------------- 1 | & 2 | color: rgb(0, 1, 0) 3 | -------------------------------------------------------------------------------- /tests/dummy/app/sass/template.hbs: -------------------------------------------------------------------------------- 1 | {{sass/base-rules}} 2 | -------------------------------------------------------------------------------- /tests/dummy/app/scss/nested/styles.scss: -------------------------------------------------------------------------------- 1 | & { 2 | color: rgb(0, 2, 0); 3 | } 4 | -------------------------------------------------------------------------------- /tests/dummy/app/scss/styles.scss: -------------------------------------------------------------------------------- 1 | & { 2 | color: rgb(0, 1, 0); 3 | } 4 | -------------------------------------------------------------------------------- /tests/dummy/app/scss/template.hbs: -------------------------------------------------------------------------------- 1 | {{scss/base-rules}} 2 | {{scss/for-loop}} 3 | -------------------------------------------------------------------------------- /tests/dummy/app/styl/nested/styles.styl: -------------------------------------------------------------------------------- 1 | & 2 | color: rgb(0, 2, 0); 3 | 4 | -------------------------------------------------------------------------------- /tests/dummy/app/styl/styles.styl: -------------------------------------------------------------------------------- 1 | & 2 | color rgb(0, 1, 0) 3 | -------------------------------------------------------------------------------- /tests/dummy/app/styl/template.hbs: -------------------------------------------------------------------------------- 1 | {{styl/base-rules}} 2 | -------------------------------------------------------------------------------- /tests/dummy/app/styles/app.css: -------------------------------------------------------------------------------- 1 | @import 'pod-styles.css' 2 | -------------------------------------------------------------------------------- /tests/dummy/app/styles/app.less: -------------------------------------------------------------------------------- 1 | @import 'pod-styles.less'; 2 | -------------------------------------------------------------------------------- /tests/dummy/app/styles/app.sass: -------------------------------------------------------------------------------- 1 | @import 'pod-styles.sass' 2 | -------------------------------------------------------------------------------- /tests/dummy/app/styles/app.scss: -------------------------------------------------------------------------------- 1 | @import 'pod-styles.scss'; 2 | -------------------------------------------------------------------------------- /tests/dummy/app/styles/app.styl: -------------------------------------------------------------------------------- 1 | @import 'pod-styles' 2 | -------------------------------------------------------------------------------- /tests/dummy/app/styles/component-styles/classic-structure.scss: -------------------------------------------------------------------------------- 1 | .classic-structure { 2 | color: rgb(0, 0, 1); 3 | } 4 | -------------------------------------------------------------------------------- /tests/dummy/app/styles/component-styles/nested/classic-structure-nested.scss: -------------------------------------------------------------------------------- 1 | .classic-structure-nested { 2 | color: rgb(0, 0, 1); 3 | } 4 | -------------------------------------------------------------------------------- /tests/dummy/app/template-style-only/template.hbs: -------------------------------------------------------------------------------- 1 | {{template-and-style}} 2 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/application.hbs: -------------------------------------------------------------------------------- 1 |
2 | {{outlet}} 3 |
4 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/classic-structure-nested.hbs: -------------------------------------------------------------------------------- 1 | {{nested/classic-structure-nested}} 2 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/classic-structure.hbs: -------------------------------------------------------------------------------- 1 | {{classic-structure}} 2 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/components/classic-structure.hbs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/components/nested/classic-structure-nested.hbs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/dummy/app/unique-component-paths/-components/test-component/styles.scss: -------------------------------------------------------------------------------- 1 | h1 { 2 | color: rgb(0, 0, 14); 3 | } 4 | -------------------------------------------------------------------------------- /tests/dummy/app/unique-component-paths/-components/test-component/template.hbs: -------------------------------------------------------------------------------- 1 |

my color should be rgb(0, 0, 14)

2 | -------------------------------------------------------------------------------- /tests/dummy/app/unique-component-paths/template.hbs: -------------------------------------------------------------------------------- 1 | {{unique-component-paths/-components/test-component}} 2 | -------------------------------------------------------------------------------- /tests/dummy/config/environment.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(environment) { 4 | let ENV = { 5 | modulePrefix: 'dummy', 6 | podModulePrefix: 'dummy', 7 | environment, 8 | rootURL: '/', 9 | locationType: 'auto', 10 | EmberENV: { 11 | FEATURES: { 12 | // Here you can enable experimental features on an ember canary build 13 | // e.g. 'with-controller': true 14 | }, 15 | EXTEND_PROTOTYPES: { 16 | // Prevent Ember Data from overriding Date.parse. 17 | Date: false 18 | } 19 | }, 20 | 21 | APP: { 22 | // Here you can pass flags/options to your application instance 23 | // when it is created 24 | } 25 | }; 26 | 27 | if (environment === 'development') { 28 | // ENV.APP.LOG_RESOLVER = true; 29 | // ENV.APP.LOG_ACTIVE_GENERATION = true; 30 | // ENV.APP.LOG_TRANSITIONS = true; 31 | // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; 32 | // ENV.APP.LOG_VIEW_LOOKUPS = true; 33 | } 34 | 35 | if (environment === 'test') { 36 | // Testem prefers this... 37 | ENV.locationType = 'none'; 38 | 39 | // keep test console output quieter 40 | ENV.APP.LOG_ACTIVE_GENERATION = false; 41 | ENV.APP.LOG_VIEW_LOOKUPS = false; 42 | 43 | ENV.APP.rootElement = '#ember-testing'; 44 | ENV.APP.autoboot = false; 45 | } 46 | 47 | return ENV; 48 | }; 49 | -------------------------------------------------------------------------------- /tests/dummy/config/optional-features.json: -------------------------------------------------------------------------------- 1 | { 2 | "application-template-wrapper": true, 3 | "default-async-observers": false, 4 | "jquery-integration": true, 5 | "template-only-glimmer-components": false 6 | } 7 | -------------------------------------------------------------------------------- /tests/dummy/config/targets.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const browsers = [ 4 | 'last 1 Chrome versions', 5 | 'last 1 Firefox versions', 6 | 'last 1 Safari versions' 7 | ]; 8 | 9 | const isCI = !!process.env.CI; 10 | const isProduction = process.env.EMBER_ENV === 'production'; 11 | 12 | if (isCI || isProduction) { 13 | browsers.push('ie 11'); 14 | } 15 | 16 | module.exports = { 17 | browsers 18 | }; 19 | -------------------------------------------------------------------------------- /tests/dummy/lib/no-style-files-yet/addon/components/no-style/component.js: -------------------------------------------------------------------------------- 1 | import Component from '@ember/component'; 2 | 3 | import layout from './template'; 4 | 5 | export default Component.extend({ 6 | layout 7 | }); 8 | -------------------------------------------------------------------------------- /tests/dummy/lib/no-style-files-yet/addon/components/no-style/template.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tests/dummy/lib/no-style-files-yet/app/components/no-style/component.js: -------------------------------------------------------------------------------- 1 | export { default } from 'no-style-files-yet/components/no-style/component'; 2 | -------------------------------------------------------------------------------- /tests/dummy/lib/no-style-files-yet/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 'use strict'; 3 | 4 | module.exports = { 5 | name: 'no-style-files-yet', 6 | 7 | isDevelopingAddon: function() { 8 | return true; 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /tests/dummy/lib/no-style-files-yet/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "no-style-files-yet", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "ember-cli-babel": "*", 6 | "ember-cli-htmlbars": "*", 7 | "ember-cli-styles-preprocessor": "*" 8 | }, 9 | "keywords": [ 10 | "ember-addon" 11 | ], 12 | "ember-addon": { 13 | "paths": [ 14 | "../../../.." 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/dummy/lib/second-test-addon/addon/components/second-addon-less/component.js: -------------------------------------------------------------------------------- 1 | import Component from '@ember/component'; 2 | 3 | import layout from './template'; 4 | 5 | export default Component.extend({ 6 | layout 7 | }); 8 | -------------------------------------------------------------------------------- /tests/dummy/lib/second-test-addon/addon/components/second-addon-less/styles.less: -------------------------------------------------------------------------------- 1 | .base { 2 | color: rgb(1, 0, 1); 3 | 4 | .nested { 5 | color: rgb(1, 0, 2); 6 | } 7 | } 8 | 9 | span { 10 | > span { 11 | > span { 12 | color: rgb(1, 0, 3); 13 | } 14 | } 15 | } 16 | 17 | & { 18 | &__element { 19 | color: rgb(1, 0, 4); 20 | 21 | &--variant { 22 | color: rgb(1, 0, 5); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/dummy/lib/second-test-addon/addon/components/second-addon-less/template.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ohohohohohohoh 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tests/dummy/lib/second-test-addon/addon/styles/addon.less: -------------------------------------------------------------------------------- 1 | @import 'pod-styles'; 2 | -------------------------------------------------------------------------------- /tests/dummy/lib/second-test-addon/app/components/second-addon-less/component.js: -------------------------------------------------------------------------------- 1 | export { default } from 'second-test-addon/components/second-addon-less/component'; 2 | -------------------------------------------------------------------------------- /tests/dummy/lib/second-test-addon/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 'use strict'; 3 | 4 | module.exports = { 5 | name: 'second-test-addon', 6 | 7 | isDevelopingAddon: function() { 8 | return true; 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /tests/dummy/lib/second-test-addon/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "second-test-addon", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "ember-cli-babel": "*", 6 | "ember-cli-htmlbars": "*", 7 | "ember-cli-styles-preprocessor": "*" 8 | }, 9 | "keywords": [ 10 | "ember-addon" 11 | ], 12 | "ember-addon": { 13 | "paths": [ 14 | "../../../.." 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/dummy/lib/test-addon/addon/components/addon-scss/component.js: -------------------------------------------------------------------------------- 1 | import Component from '@ember/component'; 2 | 3 | import layout from './template'; 4 | 5 | export default Component.extend({ 6 | layout 7 | }); 8 | -------------------------------------------------------------------------------- /tests/dummy/lib/test-addon/addon/components/addon-scss/styles.scss: -------------------------------------------------------------------------------- 1 | .base { 2 | color: rgb(1, 0, 1); 3 | 4 | .nested { 5 | color: rgb(1, 0, 2); 6 | } 7 | } 8 | 9 | span { 10 | > span { 11 | > span { 12 | color: rgb(1, 0, 3); 13 | } 14 | } 15 | } 16 | 17 | & { 18 | &__element { 19 | color: rgb(1, 0, 4); 20 | 21 | &--variant { 22 | color: rgb(1, 0, 5); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/dummy/lib/test-addon/addon/components/addon-scss/template.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | memeemeemm 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tests/dummy/lib/test-addon/addon/styles/addon.scss: -------------------------------------------------------------------------------- 1 | @import 'pod-styles.scss'; 2 | -------------------------------------------------------------------------------- /tests/dummy/lib/test-addon/app/components/addon-scss/component.js: -------------------------------------------------------------------------------- 1 | export { default } from 'test-addon/components/addon-scss/component'; 2 | -------------------------------------------------------------------------------- /tests/dummy/lib/test-addon/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 'use strict'; 3 | 4 | module.exports = { 5 | name: 'test-addon', 6 | 7 | isDevelopingAddon: function() { 8 | return true; 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /tests/dummy/lib/test-addon/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-addon", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "ember-cli-babel": "*", 6 | "ember-cli-htmlbars": "*", 7 | "ember-cli-styles-preprocessor": "*" 8 | }, 9 | "keywords": [ 10 | "ember-addon" 11 | ], 12 | "ember-addon": { 13 | "paths": [ 14 | "../../../.." 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/dummy/public/crossdomain.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /tests/dummy/public/robots.txt: -------------------------------------------------------------------------------- 1 | # http://www.robotstxt.org 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /tests/helpers/destroy-app.js: -------------------------------------------------------------------------------- 1 | import { run } from '@ember/runloop'; 2 | 3 | export default function destroyApp(application) { 4 | run(application, 'destroy'); 5 | } 6 | -------------------------------------------------------------------------------- /tests/helpers/module-for-acceptance.js: -------------------------------------------------------------------------------- 1 | import { module } from 'qunit'; 2 | import { resolve } from 'rsvp'; 3 | import startApp from '../helpers/start-app'; 4 | import destroyApp from '../helpers/destroy-app'; 5 | 6 | export default function(name, options = {}) { 7 | module(name, { 8 | beforeEach() { 9 | this.application = startApp(); 10 | 11 | if (options.beforeEach) { 12 | return options.beforeEach.apply(this, arguments); 13 | } 14 | }, 15 | 16 | afterEach() { 17 | let afterEach = options.afterEach && options.afterEach.apply(this, arguments); 18 | return resolve(afterEach).then(() => destroyApp(this.application)); 19 | } 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /tests/helpers/resolver.js: -------------------------------------------------------------------------------- 1 | import Resolver from '../../resolver'; 2 | import config from '../../config/environment'; 3 | 4 | const resolver = Resolver.create(); 5 | 6 | resolver.namespace = { 7 | modulePrefix: config.modulePrefix, 8 | podModulePrefix: config.podModulePrefix 9 | }; 10 | 11 | export default resolver; 12 | -------------------------------------------------------------------------------- /tests/helpers/start-app.js: -------------------------------------------------------------------------------- 1 | import Application from '../../app'; 2 | import config from '../../config/environment'; 3 | import { run } from '@ember/runloop'; 4 | 5 | export default function startApp(attrs) { 6 | let attributes = Object.assign({}, config.APP); 7 | attributes.autoboot = true; 8 | attributes = Object.assign(attributes, attrs); // use defaults, but you can override; 9 | 10 | return run(() => { 11 | let application = Application.create(attributes); 12 | application.setupForTesting(); 13 | application.injectTestHelpers(); 14 | return application; 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dummy Tests 7 | 8 | 9 | 10 | {{content-for "head"}} 11 | {{content-for "test-head"}} 12 | 13 | 14 | 15 | 16 | 17 | {{content-for "head-footer"}} 18 | {{content-for "test-head-footer"}} 19 | 20 | 21 | {{content-for "body"}} 22 | {{content-for "test-body"}} 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | {{content-for "body-footer"}} 31 | {{content-for "test-body-footer"}} 32 | 33 | 34 | -------------------------------------------------------------------------------- /tests/test-helper.js: -------------------------------------------------------------------------------- 1 | import Application from '../app'; 2 | import config from '../config/environment'; 3 | import { setApplication } from '@ember/test-helpers'; 4 | import { start } from 'ember-qunit'; 5 | 6 | setApplication(Application.create(config.APP)); 7 | 8 | start(); 9 | --------------------------------------------------------------------------------