├── .editorconfig ├── .github ├── renovate.json5 └── workflows │ ├── ci.yml │ ├── fixture-tests.yml │ ├── plan-release.yml │ └── publish.yml ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc.js ├── .release-plan.json ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── RELEASE.md ├── config └── ember-cli-update.json ├── docs ├── architecture-overview.md ├── css-isolation.md └── lint-rules.md ├── ember-scoped-css-compat ├── .editorconfig ├── .ember-cli ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .npmignore ├── .prettierignore ├── .prettierrc.js ├── .stylelintignore ├── .stylelintrc.js ├── .template-lintrc.js ├── .watchmanconfig ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── addon │ └── .gitkeep ├── app │ └── .gitkeep ├── ember-cli-build.js ├── index.js ├── package.json ├── pnpm-lock.yaml └── testem.js ├── ember-scoped-css ├── .eslintignore ├── .eslintrc.cjs ├── .gitignore ├── .prettierignore ├── .prettierrc.cjs ├── CHANGELOG.md ├── addon-main.cjs ├── build.mjs ├── build.sh ├── classic-app-support │ └── helpers │ │ └── scoped-class.js ├── package.json ├── pnpm-lock.yaml ├── src │ ├── build │ │ ├── app-css-livereload-loader.js │ │ ├── app-css-loader.js │ │ ├── babel-plugin.js │ │ ├── ember-classic-support.js │ │ ├── index.js │ │ ├── scoped-css-unplugin.js │ │ ├── template-plugin.js │ │ └── vite.js │ ├── lib │ │ ├── css │ │ │ └── utils.js │ │ ├── findCssInJs.js │ │ ├── getClassesTagsFromCss.js │ │ ├── getImportedCssFiles.js │ │ ├── isInsideGlobal.js │ │ ├── path │ │ │ ├── hash-from-absolute-path.js │ │ │ ├── hash-from-absolute-path.test.ts │ │ │ ├── hash-from-module-path.js │ │ │ ├── template-transform-paths.js │ │ │ ├── template-transform-paths.test.ts │ │ │ ├── utils.appPath.test.ts │ │ │ ├── utils.findWorkspacePath.test.ts │ │ │ ├── utils.hashFrom.test.ts │ │ │ ├── utils.isRelevantFile.test.ts │ │ │ ├── utils.js │ │ │ └── utils.paths.test.ts │ │ ├── renameClass.js │ │ ├── replaceGlimmerAst.js │ │ ├── replaceHbsInJs.js │ │ ├── rewriteCss.js │ │ └── rewriteHbs.js │ ├── noop.js │ ├── runtime │ │ ├── index.ts │ │ └── test-support.ts │ └── template-lint │ │ └── plugin.js ├── template-registry.d.ts ├── tsconfig.json └── vitest.config.mts ├── package.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── test-apps ├── classic-app ├── .editorconfig ├── .ember-cli ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .prettierignore ├── .prettierrc.js ├── .template-lintrc.js ├── .watchmanconfig ├── README.md ├── app │ ├── app.js │ ├── components │ │ ├── .gitkeep │ │ ├── component-at-class.css │ │ ├── component-at-class.hbs │ │ ├── dynamic-attribute.css │ │ ├── dynamic-attribute.hbs │ │ ├── face.hbs │ │ ├── face.module.css │ │ ├── has-at-class.hbs │ │ ├── header.css │ │ ├── header.hbs │ │ ├── header.js │ │ ├── in-app │ │ │ ├── at-class-ts │ │ │ │ ├── calls-has-at-class.css │ │ │ │ ├── calls-has-at-class.gts │ │ │ │ └── has-at-class.gts │ │ │ ├── basic.css │ │ │ ├── basic.gts │ │ │ └── misuse │ │ │ │ └── no-css.hbs │ │ ├── scoped.css │ │ ├── scoped.hbs │ │ ├── show-time.css │ │ ├── show-time.gjs │ │ ├── subexpression.css │ │ ├── subexpression.gjs │ │ ├── template-only.css │ │ └── template-only.hbs │ ├── controllers │ │ ├── .gitkeep │ │ └── application.js │ ├── helpers │ │ └── .gitkeep │ ├── index.html │ ├── models │ │ └── .gitkeep │ ├── router.js │ ├── routes │ │ └── .gitkeep │ ├── styles │ │ └── app.css │ └── templates │ │ └── application.hbs ├── config │ ├── ember-cli-update.json │ ├── environment.js │ ├── optional-features.json │ └── targets.js ├── ember-cli-build.js ├── package.json ├── pnpm-lock.yaml ├── public │ └── robots.txt ├── testem.js └── tests │ ├── index.html │ ├── shared-scenarios │ ├── from-v2-addon-ts │ │ ├── at-class-test.gjs │ │ ├── strict-class-test.gjs │ │ ├── strict-test.gjs │ │ └── v2-addon-ts-with-a-class-test.js │ ├── from-v2-addon │ │ ├── alert-from-v2-addon-test.js │ │ └── at-class-test.gjs │ └── in-app │ │ ├── at-class-test.gts │ │ ├── basic-test.gts │ │ ├── component-at-class-test.gjs │ │ ├── dynamic-attribute-test.js │ │ ├── header-test.js │ │ ├── misuse-test.js │ │ ├── scoped-test.js │ │ ├── show-time-test.js │ │ ├── subexpression-test.gjs │ │ └── template-only-test.js │ └── test-helper.js ├── embroider-app ├── .editorconfig ├── .ember-cli ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .prettierignore ├── .prettierrc.js ├── .template-lintrc.js ├── .watchmanconfig ├── README.md ├── app │ ├── app.js │ ├── components │ │ ├── forth.css │ │ ├── forth.gjs │ │ ├── in-app │ │ │ ├── at-class-ts │ │ │ │ ├── calls-has-at-class.css │ │ │ │ ├── calls-has-at-class.gts │ │ │ │ └── has-at-class.gts │ │ │ ├── basic.css │ │ │ ├── basic.gts │ │ │ └── misuse │ │ │ │ └── no-css.hbs │ │ ├── my-component.css │ │ ├── my-component.hbs │ │ ├── second.css │ │ ├── second.hbs │ │ ├── template-only.css │ │ ├── template-only.hbs │ │ ├── third.gjs │ │ └── with-class.gjs │ ├── controllers │ │ ├── .gitkeep │ │ └── application.js │ ├── helpers │ │ └── .gitkeep │ ├── index.html │ ├── models │ │ └── .gitkeep │ ├── router.js │ ├── routes │ │ └── .gitkeep │ ├── styles │ │ └── app.css │ └── templates │ │ ├── application.css │ │ └── application.hbs ├── config │ ├── ember-cli-update.json │ ├── ember-try.js │ ├── environment.js │ ├── optional-features.json │ └── targets.js ├── ember-cli-build.js ├── package.json ├── pnpm-lock.yaml ├── public │ └── robots.txt ├── testem.js └── tests │ ├── application │ └── route-scoped-css-test.js │ ├── helpers │ └── index.js │ ├── index.html │ ├── integration │ ├── alert-from-v2-addon-test.js │ ├── in-app │ │ ├── at-class-test.gts │ │ └── basic-test.gts │ ├── my-component-test.js │ ├── second-test.js │ └── template-only-test.js │ ├── test-helper.js │ └── unit │ └── .gitkeep ├── pods-classic-app ├── .editorconfig ├── .ember-cli ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .prettierignore ├── .prettierrc.js ├── .stylelintignore ├── .stylelintrc.js ├── .template-lintrc.js ├── .watchmanconfig ├── README.md ├── app │ ├── app.js │ ├── components │ │ └── .gitkeep │ ├── controllers │ │ └── .gitkeep │ ├── helpers │ │ └── .gitkeep │ ├── index.html │ ├── models │ │ └── .gitkeep │ ├── router.js │ ├── routes │ │ └── application │ │ │ ├── styles.css │ │ │ └── template.hbs │ ├── styles │ │ └── app.css │ └── templates │ │ ├── foo.css │ │ └── foo.hbs ├── config │ ├── ember-cli-update.json │ ├── environment.js │ ├── optional-features.json │ └── targets.js ├── ember-cli-build.js ├── package.json ├── pnpm-lock.yaml ├── public │ └── robots.txt ├── testem.js └── tests │ ├── application │ └── route-scoped-css-test.js │ ├── helpers │ └── index.js │ ├── index.html │ ├── integration │ └── .gitkeep │ ├── test-helper.js │ └── unit │ └── .gitkeep ├── pods-embroider-app ├── .editorconfig ├── .ember-cli ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .prettierignore ├── .prettierrc.js ├── .stylelintignore ├── .stylelintrc.js ├── .template-lintrc.js ├── .watchmanconfig ├── README.md ├── app │ ├── app.js │ ├── components │ │ └── .gitkeep │ ├── controllers │ │ └── .gitkeep │ ├── helpers │ │ └── .gitkeep │ ├── index.html │ ├── models │ │ └── .gitkeep │ ├── router.js │ ├── routes │ │ └── application │ │ │ ├── styles.css │ │ │ └── template.hbs │ └── styles │ │ └── app.css ├── config │ ├── ember-cli-update.json │ ├── environment.js │ ├── optional-features.json │ └── targets.js ├── ember-cli-build.js ├── package.json ├── pnpm-lock.yaml ├── public │ └── robots.txt ├── testem.js └── tests │ ├── application │ └── route-scoped-css-test.js │ ├── helpers │ └── index.js │ ├── index.html │ ├── integration │ └── .gitkeep │ ├── test-helper.js │ └── unit │ └── .gitkeep ├── v2-addon-ts ├── .eslintignore ├── .eslintrc.cjs ├── .gitignore ├── .prettierignore ├── .prettierrc.js ├── .template-lintrc.cjs ├── addon-main.cjs ├── babel.config.json ├── fixtures │ └── expected-dist │ │ └── components │ │ ├── strict-class.css │ │ ├── strict-class.js │ │ ├── strict.css │ │ └── strict.js ├── package.json ├── pnpm-lock.yaml ├── rollup.config.mjs ├── src │ ├── components │ │ ├── at-class-ts │ │ │ ├── at-class-more-complex.css │ │ │ ├── at-class-more-complex.hbs │ │ │ ├── component-at-class.css │ │ │ ├── component-at-class.hbs │ │ │ ├── has-at-class.hbs │ │ │ └── has-at-class.ts │ │ ├── classic-template-only │ │ │ ├── index.css │ │ │ └── index.hbs │ │ ├── strict-class.css │ │ ├── strict-class.gts │ │ ├── strict.css │ │ ├── strict.gts │ │ ├── with-a-class.css │ │ ├── with-a-class.hbs │ │ └── with-a-class.ts │ └── index.ts ├── tsconfig.json └── unpublished-development-types │ └── index.d.ts ├── v2-addon ├── .eslintignore ├── .eslintrc.cjs ├── .gitignore ├── .prettierignore ├── .prettierrc.cjs ├── .template-lintrc.cjs ├── addon-main.cjs ├── babel.config.json ├── fixtures │ └── expected-dist │ │ └── components │ │ ├── alert.css │ │ ├── alert.js │ │ ├── footer.js │ │ ├── time.css │ │ └── time.js ├── package.json ├── pnpm-lock.yaml ├── rollup.config.mjs └── src │ ├── components │ ├── alert.css │ ├── alert.hbs │ ├── at-class │ │ ├── component-at-class.css │ │ ├── component-at-class.hbs │ │ └── has-at-class.hbs │ ├── footer.css │ ├── footer.gjs │ ├── header.gjs │ ├── time.css │ └── time.gts │ └── index.js ├── vite-app-with-compat ├── .gitignore ├── .prettierignore ├── .prettierrc.cjs ├── .template-lintrc.cjs ├── babel.config.cjs ├── config │ ├── optional-features.json │ └── targets.cjs ├── ember-cli-build.cjs ├── eslint.config.js ├── index.html ├── package.json ├── pnpm-lock.yaml ├── src │ ├── app.js │ ├── components │ │ ├── forth.css │ │ ├── forth.gjs │ │ ├── in-app │ │ │ ├── at-class-ts │ │ │ │ ├── calls-has-at-class.css │ │ │ │ ├── calls-has-at-class.gts │ │ │ │ └── has-at-class.gts │ │ │ ├── basic.css │ │ │ ├── basic.gts │ │ │ ├── legacy-co-located-js.css │ │ │ ├── legacy-co-located-js.hbs │ │ │ ├── legacy-co-located-js.js │ │ │ ├── legacy-co-located.css │ │ │ ├── legacy-co-located.hbs │ │ │ ├── legacy-co-located.ts │ │ │ ├── legacy-conditional.css │ │ │ ├── legacy-conditional.hbs │ │ │ ├── legacy.css │ │ │ └── legacy.hbs │ │ ├── third.gjs │ │ └── with-class.gjs │ ├── config.js │ ├── registry.js │ └── router.js ├── testem.cjs ├── tests │ ├── from-v2-addon-ts │ │ └── strict-class-test.gts │ ├── in-app │ │ ├── at-class-test.gts │ │ ├── basic-test.gts │ │ ├── legacy-co-located-js-test.gts │ │ ├── legacy-co-located-test.gts │ │ ├── legacy-conditional-test.gts │ │ └── legacy-test.gts │ ├── index.html │ └── test-helper.js └── vite.config.js └── vite-app ├── .gitignore ├── .prettierignore ├── .prettierrc.cjs ├── .template-lintrc.cjs ├── babel.config.cjs ├── config ├── optional-features.json └── targets.js ├── eslint.config.js ├── index.html ├── package.json ├── pnpm-lock.yaml ├── src ├── app.js ├── components │ ├── forth.css │ ├── forth.gjs │ ├── in-app │ │ ├── at-class-ts │ │ │ ├── calls-has-at-class.css │ │ │ ├── calls-has-at-class.gts │ │ │ └── has-at-class.gts │ │ ├── basic.css │ │ └── basic.gts │ ├── third.gjs │ └── with-class.gjs ├── config.js ├── registry.js └── router.js ├── testem.cjs ├── tests ├── from-v2-addon-ts │ └── strict-class-test.gts ├── in-app │ ├── at-class-test.gts │ └── basic-test.gts ├── index.html └── test-helper.js └── vite.config.js /.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 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | indent_style = space 13 | indent_size = 2 14 | 15 | [*.hbs] 16 | insert_final_newline = false 17 | 18 | [*.{diff,md}] 19 | trim_trailing_whitespace = false 20 | -------------------------------------------------------------------------------- /.github/renovate.json5: -------------------------------------------------------------------------------- 1 | // Docs: 2 | // https://docs.renovatebot.com/configuration-options/ 3 | { 4 | "extends": [ 5 | "github>NullVoxPopuli/renovate:npm.json5" 6 | ], 7 | "packageRules": [ 8 | { 9 | "matchPaths": ["test-apps/*/package.json"], 10 | "enabled": false 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /.github/workflows/fixture-tests.yml: -------------------------------------------------------------------------------- 1 | name: Fixture Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - master 8 | pull_request: {} 9 | 10 | concurrency: 11 | group: fixture-tests-${{ github.head_ref || github.ref }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | test: 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - uses: wyvox/action@v1 20 | - run: pnpm test:fixture 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | dist/ 5 | 6 | # dependencies 7 | node_modules/ 8 | 9 | # misc 10 | .log/ 11 | /.env* 12 | /.pnp* 13 | /.pnpm-debug.log 14 | /.sass-cache 15 | .eslintcache 16 | /connect.lock 17 | /coverage/ 18 | /libpeerconnection.log 19 | /npm-debug.log* 20 | /testem.log 21 | /yarn-error.log 22 | 23 | # ember-try 24 | /.node_modules.ember-try/ 25 | /package.json.ember-try 26 | /yarn.lock.ember-try 27 | 28 | .DS_Store 29 | .vscode 30 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # Simulate new project installs 2 | resolution-mode=highest 3 | 4 | # as a library, we want to make sure we explicitly handle peers, 5 | # and not rely on hidden behavior of package-managers. 6 | auto-install-peers=false 7 | 8 | # we never want to use packages from the registry over what's in the workspace 9 | prefer-workspaces-packages=true 10 | resolve-peers-from-workspace-root=false 11 | dedupe-peer-dependents=true 12 | hoist-workspace-packages=false 13 | 14 | # default is true, we do this to try to have more isolation 15 | # since we test with incompatible sets of TS types. 16 | shared-workspace-lockfile=false 17 | 18 | ## We use so many similarly grouped peers, we want to make the 19 | ## peer-groups easier to distinguish. 20 | ## This forces a shorter sha for all groups (vs the default of 1000) 21 | ## 22 | peers-suffix-max-length=40 23 | virtual-store-dir-max-length=40 24 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 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 | .eslintcache 17 | .lint-todo/ 18 | .github/ 19 | 20 | # ember-try 21 | /.node_modules.ember-try/ 22 | /bower.json.ember-try 23 | /npm-shrinkwrap.json.ember-try 24 | /package.json.ember-try 25 | /package-lock.json.ember-try 26 | /yarn.lock.ember-try 27 | 28 | 29 | # We don't want the changelog or lockfile changing in renovate updates to 30 | # cause CI to fail 31 | *.md 32 | *.yaml 33 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | singleQuote: true, 5 | }; 6 | -------------------------------------------------------------------------------- /.release-plan.json: -------------------------------------------------------------------------------- 1 | { 2 | "solution": { 3 | "ember-scoped-css": { 4 | "impact": "patch", 5 | "oldVersion": "0.23.2", 6 | "newVersion": "0.23.3", 7 | "tagName": "latest", 8 | "constraints": [ 9 | { 10 | "impact": "patch", 11 | "reason": "Appears in changelog section :bug: Bug Fix" 12 | } 13 | ], 14 | "pkgJSONPath": "./ember-scoped-css/package.json" 15 | }, 16 | "ember-scoped-css-compat": { 17 | "impact": "patch", 18 | "oldVersion": "10.2.0", 19 | "newVersion": "10.2.1", 20 | "tagName": "latest", 21 | "constraints": [ 22 | { 23 | "impact": "patch", 24 | "reason": "Appears in changelog section :bug: Bug Fix" 25 | } 26 | ], 27 | "pkgJSONPath": "./ember-scoped-css-compat/package.json" 28 | } 29 | }, 30 | "description": "## Release (2025-04-08)\n\n* ember-scoped-css 0.23.3 (patch)\n* ember-scoped-css-compat 10.2.1 (patch)\n\n#### :bug: Bug Fix\n* `ember-scoped-css-compat`, `ember-scoped-css`\n * [#294](https://github.com/soxhub/ember-scoped-css/pull/294) Fix issue where the vite-app scopedCSS plugin was running on library code ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n\n#### :house: Internal\n* [#296](https://github.com/soxhub/ember-scoped-css/pull/296) Drop 4.4 from testing matrix ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n\n#### Committers: 1\n- [@NullVoxPopuli](https://github.com/NullVoxPopuli)\n" 31 | } 32 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How To Contribute 2 | 3 | ## Installation 4 | 5 | - `git clone ` 6 | - `cd v2-addon` 7 | - `pnpm install` 8 | 9 | ## Linting 10 | 11 | - `pnpm lint` 12 | - `pnpm lint:fix` 13 | 14 | ## Building the addon 15 | 16 | - `cd v2-addon` 17 | - `pnpm build` 18 | 19 | ## Running tests 20 | 21 | - `cd embroider-app` 22 | - `pnpm test` – Runs the test suite on the current Ember version 23 | - `pnpm test:watch` – Runs the test suite in "watch mode" 24 | 25 | ## Running the test application 26 | 27 | - `cd embroider-app` 28 | - `pnpm start` 29 | - Visit the test application at [http://localhost:4200](http://localhost:4200). 30 | 31 | For more information on using ember-cli, visit [https://cli.emberjs.com/release/](https://cli.emberjs.com/release/). 32 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2023 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 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Release Process 2 | 3 | Releases in this repo are mostly automated using [release-plan](https://github.com/embroider-build/release-plan/). Once you label all your PRs correctly (see below) you will have an automatically generated PR that updates your CHANGELOG.md file and a `.release-plan.json` that is used to prepare the release once the PR is merged. 4 | 5 | ## Preparation 6 | 7 | Since the majority of the actual release process is automated, the remaining tasks before releasing are: 8 | 9 | - correctly labeling **all** pull requests that have been merged since the last release 10 | - updating pull request titles so they make sense to our users 11 | 12 | Some great information on why this is important can be found at [keepachangelog.com](https://keepachangelog.com/en/1.1.0/), but the overall 13 | guiding principle here is that changelogs are for humans, not machines. 14 | 15 | When reviewing merged PR's the labels to be used are: 16 | 17 | - breaking - Used when the PR is considered a breaking change. 18 | - enhancement - Used when the PR adds a new feature or enhancement. 19 | - bug - Used when the PR fixes a bug included in a previous release. 20 | - documentation - Used when the PR adds or updates documentation. 21 | - internal - Internal changes or things that don't fit in any other category. 22 | 23 | **Note:** `release-plan` requires that **all** PRs are labeled. If a PR doesn't fit in a category it's fine to label it as `internal` 24 | 25 | ## Release 26 | 27 | Once the prep work is completed, the actual release is straight forward: you just need to merge the open [Plan Release](https://github.com/soxhub/ember-scoped-css/pulls?q=is%3Apr+is%3Aopen+%22Prepare+Release%22+in%3Atitle) PR 28 | -------------------------------------------------------------------------------- /config/ember-cli-update.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": "1.0.0", 3 | "packages": [ 4 | { 5 | "name": "@embroider/addon-blueprint", 6 | "version": "1.5.0", 7 | "blueprints": [ 8 | { 9 | "name": "@embroider/addon-blueprint", 10 | "isBaseBlueprint": true, 11 | "options": [ 12 | "--pnpm", 13 | "--ci-provider=github" 14 | ] 15 | } 16 | ] 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /docs/lint-rules.md: -------------------------------------------------------------------------------- 1 | ## scoped-class-helper 2 | 3 | This rule checks if `scoped-class` helper has one positional param of type StringLiteral. 4 | The following example shows the correct use of the helper: 5 | 6 | ```hbs 7 | 8 | ``` 9 | 10 | ### Examples 11 | 12 | This rule forbids the following: 13 | 14 | 1. Wrong number of positional params 15 | 16 | ```hbs 17 | 18 | 19 | ``` 20 | 21 | 2. Dynamic properties 22 | 23 | ```hbs 24 | 25 | ``` 26 | -------------------------------------------------------------------------------- /ember-scoped-css-compat/.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 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | indent_style = space 13 | indent_size = 2 14 | 15 | [*.hbs] 16 | insert_final_newline = false 17 | 18 | [*.{diff,md}] 19 | trim_trailing_whitespace = false 20 | -------------------------------------------------------------------------------- /ember-scoped-css-compat/.ember-cli: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | Ember CLI sends analytics information by default. The data is completely 4 | anonymous, but there are times when you might want to disable this behavior. 5 | 6 | Setting `disableAnalytics` to true will prevent any data from being sent. 7 | */ 8 | "disableAnalytics": false, 9 | 10 | /** 11 | Setting `isTypeScriptProject` to true will force the blueprint generators to generate TypeScript 12 | rather than JavaScript by default, when a TypeScript version of a given blueprint is available. 13 | */ 14 | "isTypeScriptProject": false 15 | } 16 | -------------------------------------------------------------------------------- /ember-scoped-css-compat/.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 | .eslintcache 18 | 19 | # ember-try 20 | /.node_modules.ember-try/ 21 | /bower.json.ember-try 22 | /npm-shrinkwrap.json.ember-try 23 | /package.json.ember-try 24 | /package-lock.json.ember-try 25 | /yarn.lock.ember-try 26 | -------------------------------------------------------------------------------- /ember-scoped-css-compat/.eslintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { configs } = require('@nullvoxpopuli/eslint-configs'); 4 | 5 | const ember = configs.ember(); 6 | 7 | // accommodates: JS, TS, App, Addon, and V2 Addon 8 | module.exports = { 9 | overrides: [...ember.overrides], 10 | }; 11 | -------------------------------------------------------------------------------- /ember-scoped-css-compat/.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 | /.env* 13 | /.pnp* 14 | /.sass-cache 15 | /.eslintcache 16 | /connect.lock 17 | /coverage/ 18 | /libpeerconnection.log 19 | /npm-debug.log* 20 | /testem.log 21 | /yarn-error.log 22 | 23 | # ember-try 24 | /.node_modules.ember-try/ 25 | /bower.json.ember-try 26 | /npm-shrinkwrap.json.ember-try 27 | /package.json.ember-try 28 | /package-lock.json.ember-try 29 | /yarn.lock.ember-try 30 | 31 | # broccoli-debug 32 | /DEBUG/ 33 | -------------------------------------------------------------------------------- /ember-scoped-css-compat/.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 | /.env* 13 | /.eslintcache 14 | /.eslintignore 15 | /.eslintrc.js 16 | /.git/ 17 | /.github/ 18 | /.gitignore 19 | /.prettierignore 20 | /.prettierrc.js 21 | /.stylelintignore 22 | /.stylelintrc.js 23 | /.template-lintrc.js 24 | /.travis.yml 25 | /.watchmanconfig 26 | /bower.json 27 | /CONTRIBUTING.md 28 | /ember-cli-build.js 29 | /testem.js 30 | /tests/ 31 | /yarn-error.log 32 | /yarn.lock 33 | .gitkeep 34 | 35 | # ember-try 36 | /.node_modules.ember-try/ 37 | /bower.json.ember-try 38 | /npm-shrinkwrap.json.ember-try 39 | /package.json.ember-try 40 | /package-lock.json.ember-try 41 | /yarn.lock.ember-try 42 | -------------------------------------------------------------------------------- /ember-scoped-css-compat/.prettierignore: -------------------------------------------------------------------------------- 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 | .eslintcache 17 | .lint-todo/ 18 | 19 | # ember-try 20 | /.node_modules.ember-try/ 21 | /bower.json.ember-try 22 | /npm-shrinkwrap.json.ember-try 23 | /package.json.ember-try 24 | /package-lock.json.ember-try 25 | /yarn.lock.ember-try 26 | 27 | # We don't want the changelog or lockfile changing in renovate updates to 28 | # cause CI to fail 29 | *.md 30 | *.yaml 31 | -------------------------------------------------------------------------------- /ember-scoped-css-compat/.prettierrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | overrides: [ 5 | { 6 | files: '*.{js,ts}', 7 | options: { 8 | singleQuote: true, 9 | }, 10 | }, 11 | ], 12 | }; 13 | -------------------------------------------------------------------------------- /ember-scoped-css-compat/.stylelintignore: -------------------------------------------------------------------------------- 1 | # unconventional files 2 | /blueprints/*/files/ 3 | 4 | # compiled output 5 | /dist/ 6 | 7 | # addons 8 | /.node_modules.ember-try/ 9 | -------------------------------------------------------------------------------- /ember-scoped-css-compat/.stylelintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | extends: ['stylelint-config-standard', 'stylelint-prettier/recommended'], 5 | }; 6 | -------------------------------------------------------------------------------- /ember-scoped-css-compat/.template-lintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | extends: 'recommended', 5 | }; 6 | -------------------------------------------------------------------------------- /ember-scoped-css-compat/.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": ["tmp", "dist"] 3 | } 4 | -------------------------------------------------------------------------------- /ember-scoped-css-compat/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How To Contribute 2 | 3 | ## Installation 4 | 5 | - `git clone ` 6 | - `cd ember-scoped-css-compat` 7 | - `npm install` 8 | 9 | ## Linting 10 | 11 | - `npm run lint` 12 | - `npm run lint:fix` 13 | 14 | ## Running tests 15 | 16 | - `ember test` – Runs the test suite on the current Ember version 17 | - `ember test --server` – Runs the test suite in "watch mode" 18 | - `ember try:each` – Runs the test suite against multiple Ember versions 19 | 20 | ## Running the dummy application 21 | 22 | - `ember serve` 23 | - Visit the dummy application at [http://localhost:4200](http://localhost:4200). 24 | 25 | For more information on using ember-cli, visit [https://cli.emberjs.com/release/](https://cli.emberjs.com/release/). 26 | -------------------------------------------------------------------------------- /ember-scoped-css-compat/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2023 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 | -------------------------------------------------------------------------------- /ember-scoped-css-compat/README.md: -------------------------------------------------------------------------------- 1 | # ember-scoped-css-compat 2 | 3 | [Short description of the addon.] 4 | 5 | ## Compatibility 6 | 7 | - Ember.js v4.4 or above 8 | - Ember CLI v4.4 or above 9 | - Node.js v14 or above 10 | 11 | ## Installation 12 | 13 | ``` 14 | ember install ember-scoped-css-compat 15 | ``` 16 | 17 | ## Usage 18 | 19 | [Longer description of how to use the addon in apps.] 20 | 21 | ## Contributing 22 | 23 | See the [Contributing](CONTRIBUTING.md) guide for details. 24 | 25 | ## License 26 | 27 | This project is licensed under the [MIT License](LICENSE.md). 28 | -------------------------------------------------------------------------------- /ember-scoped-css-compat/addon/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soxhub/ember-scoped-css/625bad873385b8d17e6c0b50b60d312dea5bf6a1/ember-scoped-css-compat/addon/.gitkeep -------------------------------------------------------------------------------- /ember-scoped-css-compat/app/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soxhub/ember-scoped-css/625bad873385b8d17e6c0b50b60d312dea5bf6a1/ember-scoped-css-compat/app/.gitkeep -------------------------------------------------------------------------------- /ember-scoped-css-compat/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 | const app = new EmberAddon(defaults, { 7 | // Add options here 8 | }); 9 | 10 | /* 11 | This build file specifies the options for the dummy test app of this 12 | addon, located in `/tests/dummy` 13 | This build file does *not* influence how the addon or the app using it 14 | behave. You most likely want to be modifying `./index.js` or app's build file 15 | */ 16 | 17 | const { maybeEmbroider } = require('@embroider/test-setup'); 18 | 19 | return maybeEmbroider(app, { 20 | skipBabel: [ 21 | { 22 | package: 'qunit', 23 | }, 24 | ], 25 | }); 26 | }; 27 | -------------------------------------------------------------------------------- /ember-scoped-css-compat/testem.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | test_page: 'tests/index.html?hidepassed', 5 | disable_watching: true, 6 | launch_in_ci: ['Chrome'], 7 | launch_in_dev: ['Chrome'], 8 | browser_start_timeout: 120, 9 | browser_args: { 10 | Chrome: { 11 | ci: [ 12 | // --no-sandbox is needed when running Chrome inside a container 13 | process.env.CI ? '--no-sandbox' : null, 14 | '--headless', 15 | '--disable-dev-shm-usage', 16 | '--disable-software-rasterizer', 17 | '--mute-audio', 18 | '--remote-debugging-port=0', 19 | '--window-size=1440,900', 20 | ].filter(Boolean), 21 | }, 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /ember-scoped-css/.eslintignore: -------------------------------------------------------------------------------- 1 | # unconventional js 2 | blueprints/*/files/ 3 | 4 | # compiled output 5 | dist/ 6 | declarations/ 7 | 8 | # misc 9 | coverage/ 10 | -------------------------------------------------------------------------------- /ember-scoped-css/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { configs } = require('@nullvoxpopuli/eslint-configs'); 4 | 5 | const nodeESM = configs.node(); 6 | 7 | // accommodates: JS, TS, App, Addon, and V2 Addon 8 | module.exports = { 9 | overrides: [ 10 | ...nodeESM.overrides, 11 | { 12 | files: ['./**/*.{js,ts}'], 13 | rules: { 14 | // These lints don't support one or more of 15 | // - TS 5 16 | // - `node:` imports 17 | 'import/namespace': 'off', 18 | 'import/no-cycle': 'off', 19 | 'import/named': 'off', 20 | 'import/default': 'off', 21 | 'import/no-named-as-default': 'off', 22 | 'import/no-named-as-default-member': 'off', 23 | 24 | // This doesn't support modern ESM 25 | 'n/no-missing-import': 'off', 26 | }, 27 | }, 28 | { 29 | files: ['./test/**/*.js', '**/*.test.ts'], 30 | env: { 31 | mocha: true, 32 | }, 33 | rules: { 34 | 'n/no-unpublished-import': 'off', 35 | 'node/no-unpublished-import': 'off', 36 | }, 37 | }, 38 | ], 39 | }; 40 | -------------------------------------------------------------------------------- /ember-scoped-css/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | declarations/ 3 | 4 | README.md 5 | LICENSE.md 6 | -------------------------------------------------------------------------------- /ember-scoped-css/.prettierignore: -------------------------------------------------------------------------------- 1 | # unconventional js 2 | blueprints/*/files/ 3 | 4 | # compiled output 5 | dist/ 6 | 7 | # misc 8 | coverage/ 9 | *.md 10 | *.yaml 11 | -------------------------------------------------------------------------------- /ember-scoped-css/.prettierrc.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | overrides: [ 5 | { 6 | files: '*.{js,ts,cjs,mjs,mts,cts,gts.gjs}', 7 | options: { 8 | singleQuote: true, 9 | }, 10 | }, 11 | ], 12 | }; 13 | -------------------------------------------------------------------------------- /ember-scoped-css/addon-main.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { addonV1Shim } = require('@embroider/addon-shim'); 4 | 5 | module.exports = addonV1Shim(__dirname); 6 | -------------------------------------------------------------------------------- /ember-scoped-css/build.mjs: -------------------------------------------------------------------------------- 1 | import * as esbuild from 'esbuild'; 2 | import { vitestCleaner } from 'esbuild-plugin-vitest-cleaner'; 3 | import { createRequire as topLevelCreateRequire } from 'module'; 4 | 5 | const require = topLevelCreateRequire(import.meta.url); 6 | 7 | const buildFiles = [ 8 | 'src/build/index.js', 9 | 'src/build/app-css-loader.js', 10 | 'src/build/ember-classic-support.js', 11 | 'src/build/babel-plugin.js', 12 | 'src/build/template-plugin.js', 13 | ]; 14 | 15 | const external = [...Object.keys(require('./package.json').dependencies)]; 16 | 17 | // Node, CJS 18 | await esbuild.build({ 19 | entryPoints: buildFiles, 20 | bundle: true, 21 | outdir: 'dist/cjs', 22 | format: 'cjs', 23 | platform: 'node', 24 | sourcemap: 'inline', 25 | outExtension: { '.js': '.cjs' }, 26 | external, 27 | plugins: [vitestCleaner()], 28 | }); 29 | 30 | // Runtime 31 | await esbuild.build({ 32 | entryPoints: ['src/runtime/test-support.ts', 'src/runtime/index.ts'], 33 | sourcemap: true, 34 | format: 'esm', 35 | bundle: true, 36 | external, 37 | plugins: [vitestCleaner()], 38 | outdir: 'dist/runtime', 39 | }); 40 | -------------------------------------------------------------------------------- /ember-scoped-css/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | rm -rf dist/ declarations/ 6 | 7 | cp ../README.md ./README.md 8 | cp ../LICENSE.md ./LICENSE.md 9 | 10 | node ./build.mjs 11 | 12 | # Types 13 | pnpm tsc --emitDeclarationOnly 14 | -------------------------------------------------------------------------------- /ember-scoped-css/classic-app-support/helpers/scoped-class.js: -------------------------------------------------------------------------------- 1 | export { scopedClass as default } from 'ember-scoped-css'; 2 | -------------------------------------------------------------------------------- /ember-scoped-css/src/build/app-css-loader.js: -------------------------------------------------------------------------------- 1 | // import { createUnplugin } from 'unplugin'; 2 | import { existsSync } from 'node:fs'; 3 | import path from 'node:path'; 4 | 5 | import { hashFrom, isRelevantFile } from '../lib/path/utils.js'; 6 | import rewriteCss from '../lib/rewriteCss.js'; 7 | 8 | export default async function (code) { 9 | const options = this.getOptions(); 10 | const cssPath = this.resourcePath; 11 | 12 | if (!isRelevantFile(cssPath, { ...options, cwd: this.rootContext })) { 13 | return code; 14 | } 15 | 16 | if (!cssPath.startsWith(this.rootContext)) { 17 | return code; 18 | } 19 | 20 | const cssFileName = path.basename(cssPath); 21 | 22 | const hbsPath = cssPath.replace('.css', '.hbs'); 23 | const gjsPath = cssPath.replace('.css', '.js'); 24 | const gtsPath = cssPath.replace('.css', '.ts'); 25 | 26 | if (existsSync(gjsPath) || existsSync(gtsPath) || existsSync(hbsPath)) { 27 | const postfix = hashFrom(cssPath); 28 | const rewrittenCss = rewriteCss( 29 | code, 30 | postfix, 31 | cssFileName, 32 | options.layerName, 33 | ); 34 | 35 | return rewrittenCss; 36 | } 37 | 38 | return code; 39 | } 40 | -------------------------------------------------------------------------------- /ember-scoped-css/src/build/index.js: -------------------------------------------------------------------------------- 1 | export { default as babelPlugin } from './babel-plugin.js'; 2 | export { default as scopedCssUnplugin } from './scoped-css-unplugin.js'; 3 | export { createPlugin as templatePlugin } from './template-plugin.js'; 4 | -------------------------------------------------------------------------------- /ember-scoped-css/src/build/vite.js: -------------------------------------------------------------------------------- 1 | import { default as scopedCssUnplugin } from './scoped-css-unplugin.js'; 2 | 3 | export const scopedCSS = scopedCssUnplugin.vite; 4 | -------------------------------------------------------------------------------- /ember-scoped-css/src/lib/css/utils.js: -------------------------------------------------------------------------------- 1 | import { existsSync, readFileSync } from 'fs'; 2 | 3 | import getClassesTagsFromCss from '../getClassesTagsFromCss.js'; 4 | 5 | /** 6 | * @param {string} cssPath path to a CSS file 7 | */ 8 | export function getCSSInfo(cssPath) { 9 | if (!existsSync(cssPath)) { 10 | return null; 11 | } 12 | 13 | let css = readFileSync(cssPath, 'utf8'); 14 | let result = getClassesTagsFromCss(css); 15 | 16 | return result; 17 | } 18 | -------------------------------------------------------------------------------- /ember-scoped-css/src/lib/findCssInJs.js: -------------------------------------------------------------------------------- 1 | import recast from 'recast'; 2 | 3 | export default function (script, removeCallExpression = false) { 4 | const ast = typeof script === 'string' ? recast.parse(script) : script; 5 | let css = ''; 6 | 7 | recast.visit(ast, { 8 | visitCallExpression(nodePath) { 9 | const node = nodePath.node; 10 | 11 | if ( 12 | node.callee.name === '__GLIMMER_STYLES' && 13 | node.arguments.length === 1 14 | ) { 15 | css = node.arguments[0].quasis[0].value.raw; 16 | 17 | if (removeCallExpression) { 18 | nodePath.prune(); 19 | 20 | return false; 21 | } 22 | } 23 | 24 | this.traverse(nodePath); 25 | }, 26 | }); 27 | 28 | return { css, ast }; 29 | } 30 | -------------------------------------------------------------------------------- /ember-scoped-css/src/lib/getClassesTagsFromCss.js: -------------------------------------------------------------------------------- 1 | import postcss from 'postcss'; 2 | import parser from 'postcss-selector-parser'; 3 | 4 | import isInsideGlobal from './isInsideGlobal.js'; 5 | 6 | function getClassesAndTags(sel, classes, tags) { 7 | const transform = (sls) => { 8 | sls.walk((selector) => { 9 | if (selector.type === 'class' && !isInsideGlobal(selector)) { 10 | classes.add(selector.value); 11 | } else if (selector.type === 'tag' && !isInsideGlobal(selector)) { 12 | tags.add(selector.value); 13 | } 14 | }); 15 | }; 16 | 17 | parser(transform).processSync(sel); 18 | } 19 | 20 | export default function getClassesTagsFromCss(css) { 21 | const classes = new Set(); 22 | const tags = new Set(); 23 | 24 | const ast = postcss.parse(css); 25 | 26 | ast.walk((node) => { 27 | if (node.type === 'rule') { 28 | getClassesAndTags(node.selector, classes, tags); 29 | } 30 | }); 31 | 32 | return { classes, tags }; 33 | } 34 | 35 | if (import.meta.vitest) { 36 | const { it, expect } = import.meta.vitest; 37 | 38 | it('should return classes and tags that are not in :global', function () { 39 | const css = '.baz :global(.foo) .bar div :global(p) { color: red; }'; 40 | const { classes, tags } = getClassesTagsFromCss(css); 41 | 42 | // classes should be baz and bar 43 | expect(classes.size).to.equal(2); 44 | expect([...classes]).to.have.members(['baz', 'bar']); 45 | expect(tags.size).to.equal(1); 46 | expect([...tags]).to.have.members(['div']); 47 | }); 48 | } 49 | -------------------------------------------------------------------------------- /ember-scoped-css/src/lib/getImportedCssFiles.js: -------------------------------------------------------------------------------- 1 | export default function (css) { 2 | const regex = /@import\s+["']?([^"')]+)["']?;/g; 3 | const importedCssPaths = []; 4 | let match; 5 | 6 | while ((match = regex.exec(css))) { 7 | const importPath = match[1]; 8 | 9 | if (!importPath.includes('http') && !importPath.startsWith('url(')) { 10 | css = css.replace(match[0], ''); 11 | importedCssPaths.unshift(importPath); 12 | } 13 | } 14 | 15 | return { 16 | css, 17 | importedCssPaths, 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /ember-scoped-css/src/lib/isInsideGlobal.js: -------------------------------------------------------------------------------- 1 | export default function isInsideGlobal(node, func) { 2 | const parent = node.parent; 3 | 4 | if (!parent) return false; 5 | if (parent.type === 'pseudo' && parent.value === ':global') return true; 6 | 7 | return isInsideGlobal(parent, func); 8 | } 9 | -------------------------------------------------------------------------------- /ember-scoped-css/src/lib/path/hash-from-absolute-path.js: -------------------------------------------------------------------------------- 1 | import { hash } from './hash-from-module-path.js'; 2 | import { appPath } from './utils.js'; 3 | 4 | export { hash } from './hash-from-module-path.js'; 5 | 6 | export function hashFromAbsolutePath(absolutePath) { 7 | /** 8 | * The whole of `appPath` ultimately transforms the `absolutePath` 9 | * into the exact string that folks will pass to `relativePath` 10 | * at runtime. 11 | */ 12 | const modulePath = appPath(absolutePath); 13 | const postfix = hash(modulePath); 14 | 15 | return postfix; 16 | } 17 | -------------------------------------------------------------------------------- /ember-scoped-css/src/lib/path/hash-from-absolute-path.test.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | 3 | import { describe, expect, it } from 'vitest'; 4 | 5 | import { hashFromAbsolutePath } from './hash-from-absolute-path.js'; 6 | import { hashFromModulePath } from './hash-from-module-path.js'; 7 | import { paths } from './utils.paths.test.js'; 8 | 9 | describe('hashFromAbsolutePath', () => { 10 | describe(`the module: "embroider-app/templates/application"`, () => { 11 | let file = 'templates/application'; 12 | let expected = 'ea418816b'; 13 | 14 | it('matches the module path', () => { 15 | let postfix = hashFromModulePath(`embroider-app/${file}`); 16 | 17 | expect(postfix).to.equal(expected); 18 | }); 19 | 20 | it('works with rewritten app', () => { 21 | let filePath = path.join( 22 | paths.embroiderApp, 23 | '/node_modules/.embroider/rewritten-app', 24 | file, 25 | ); 26 | 27 | let postfix = hashFromAbsolutePath(filePath); 28 | 29 | expect(postfix).to.equal(expected); 30 | }); 31 | 32 | it('works with direct path', () => { 33 | let filePath = path.join(paths.embroiderApp, 'app', file); 34 | let postfix = hashFromAbsolutePath(filePath); 35 | 36 | expect(postfix).to.equal(expected); 37 | }); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /ember-scoped-css/src/lib/path/hash-from-module-path.js: -------------------------------------------------------------------------------- 1 | import md5 from 'blueimp-md5'; 2 | 3 | /** 4 | * The intent of this function is to generate the suffix/postfix for the 5 | * css classes, based on the module-scoped path name. 6 | * 7 | * for example, 8 | * hash('my-app/components/foo') 9 | * instead of 10 | * hash('app/components/foo') 11 | * 12 | * (unless your app name is 'app') 13 | * 14 | * @param {string} modulePath 15 | * @returns {string} 16 | */ 17 | export function hash(modulePath) { 18 | return 'e' + md5(modulePath).substring(0, 8); 19 | } 20 | 21 | if (import.meta.vitest) { 22 | const { it, expect } = import.meta.vitest; 23 | 24 | it('should return a string', function () { 25 | const postfix = hash('foo.css'); 26 | 27 | expect(postfix).to.be.a('string'); 28 | }); 29 | 30 | it('should return a string starting with "e"', function () { 31 | const postfix = hash('foo.css'); 32 | 33 | expect(postfix).to.match(/^e/); 34 | }); 35 | 36 | it('should return a string of length 9', function () { 37 | const postfix = hash('foo.css'); 38 | 39 | expect(postfix).to.have.lengthOf(9); 40 | }); 41 | } 42 | 43 | export const hashFromModulePath = hash; 44 | -------------------------------------------------------------------------------- /ember-scoped-css/src/lib/path/utils.appPath.test.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | 3 | import { describe, expect, it } from 'vitest'; 4 | 5 | import { appPath } from './utils.js'; 6 | import { paths } from './utils.paths.test.js'; 7 | 8 | describe('appPath()', () => { 9 | it('handles embroider-re-written-app', () => { 10 | let file = path.join( 11 | paths.embroiderApp, 12 | paths.rewritten, 13 | 'templates/application', 14 | ); 15 | let result = appPath(file); 16 | 17 | expect(result).to.equal('embroider-app/templates/application'); 18 | }); 19 | 20 | it('handles extraneous /app/', () => { 21 | let file = path.join(paths.embroiderApp, 'app', 'templates/application'); 22 | let result = appPath(file); 23 | 24 | expect(result).to.equal('embroider-app/templates/application'); 25 | }); 26 | 27 | it('handles psuedo module', () => { 28 | let file = path.join(paths.embroiderApp, 'templates/application'); 29 | let result = appPath(file); 30 | 31 | expect(result).to.equal('embroider-app/templates/application'); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /ember-scoped-css/src/lib/path/utils.paths.test.ts: -------------------------------------------------------------------------------- 1 | import module from 'node:module'; 2 | import path from 'node:path'; 3 | import url from 'node:url'; 4 | 5 | import { describe, expect, it } from 'vitest'; 6 | 7 | const require = module.createRequire(import.meta.url); 8 | const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); 9 | const monorepoRoot = path.join(__dirname, '../../../../'); 10 | 11 | export const paths = { 12 | rewritten: 'node_modules/.embroider/rewritten-app', 13 | embroiderApp: path.join(monorepoRoot, 'test-apps/embroider-app'), 14 | classicApp: path.join(monorepoRoot, 'test-apps/classic-app'), 15 | v2Addon: path.join(monorepoRoot, 'test-apps/v2-addon'), 16 | viteApp: path.join(monorepoRoot, 'test-apps/vite-app'), 17 | }; 18 | 19 | describe('paths', () => { 20 | it('exists', () => { 21 | let aRequirable = path.join(paths.embroiderApp, 'ember-cli-build.js'); 22 | // would error if not found 23 | let result = require.resolve(aRequirable); 24 | 25 | expect(result).to.equal(aRequirable); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /ember-scoped-css/src/lib/renameClass.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @param {string} className 4 | * @param {string} postfix 5 | * @param {Set} [classesInCss] 6 | * @returns 7 | */ 8 | export function renameClass(className, postfix, classesInCss) { 9 | const classes = className.split(/\s+/); 10 | const renamedClasses = classes 11 | .filter((c) => c) 12 | .map((c) => c.trim()) 13 | .map((c) => { 14 | if (!classesInCss || classesInCss.has(c)) { 15 | if (c.endsWith(postfix)) return c; 16 | 17 | return c + '_' + postfix; 18 | } 19 | 20 | return c; 21 | }) 22 | .join(' '); 23 | 24 | const renamedWithPreservedSpaces = className.replace( 25 | className.trimStart().trimEnd(), 26 | renamedClasses, 27 | ); 28 | 29 | return renamedWithPreservedSpaces; 30 | } 31 | -------------------------------------------------------------------------------- /ember-scoped-css/src/noop.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file exists so that package.json#exports can have a JS file to point at 3 | * when we have types-only situations, such as with the template-registry for loose-mode Glint users 4 | */ 5 | -------------------------------------------------------------------------------- /ember-scoped-css/src/runtime/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Appends a suffix to a class name during build time. 3 | * This function is not available at runtime and is removed. 4 | * 5 | * @param {string} className the class, defined within the co-located CSS to have a suffix appended to it during build time. 6 | */ 7 | export function scopedClass(className: string): string { 8 | throw new Error( 9 | `scopedClass is not available at runtime. Cannot do anything with ${className}. If you see this message, there could be two reasons: 1) No CSS file associated with this component, or 2) The build transforms are not installed.`, 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /ember-scoped-css/template-registry.d.ts: -------------------------------------------------------------------------------- 1 | export default interface EmberScopedCSSTemplateRegistry { 2 | 'scoped-class': (className: string) => string; 3 | } 4 | -------------------------------------------------------------------------------- /ember-scoped-css/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@tsconfig/ember", "@tsconfig/strictest"], 3 | "include": ["src/**/*.ts"], 4 | "compilerOptions": { 5 | "allowJs": true, 6 | // why do eslint's types always get involved? 7 | "skipLibCheck": true, 8 | // let JS be loose 9 | "checkJs": false, 10 | "declaration": true, 11 | "emitDeclarationOnly": true, 12 | "noEmit": false, 13 | "inlineSourceMap": true, 14 | "declarationMap": true, 15 | "declarationDir": "declarations" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ember-scoped-css/vitest.config.mts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config'; 2 | 3 | export default defineConfig({ 4 | test: { 5 | includeSource: ['src/**/*.{js,ts}'], 6 | }, 7 | esbuild: { 8 | target: 'esnext', 9 | format: 'esm', 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scoped-css-root", 3 | "version": "0.0.0", 4 | "private": true, 5 | "repository": "https://github.com/soxhub/ember-scoped-css", 6 | "license": "MIT", 7 | "author": "", 8 | "scripts": { 9 | "build": "pnpm --filter '*' build", 10 | "lint": "pnpm --filter '*' lint", 11 | "lint:fix": "pnpm --filter '*' lint:fix", 12 | "prepare": "pnpm build", 13 | "start": "concurrently 'npm:start:*' --restart-after 5000 --prefix-colors cyan,white,yellow", 14 | "start:addon": "pnpm --filter v2-addon start --no-watch.clearScreen", 15 | "start:embroider-app": "pnpm --filter embroider-app start", 16 | "test": "pnpm --filter '*' test", 17 | "test:ember": "pnpm --filter './test-apps/*' test:ember", 18 | "test:fixture": "pnpm --filter './test-apps/*' test:fixture" 19 | }, 20 | "devDependencies": { 21 | "concurrently": "^9.1.2", 22 | "ember-source": "^6.2.0", 23 | "prettier": "^3.5.1", 24 | "release-plan": "^0.16.0" 25 | }, 26 | "packageManager": "pnpm@10.8.0", 27 | "volta": { 28 | "node": "22.4.1", 29 | "pnpm": "10.8.0" 30 | }, 31 | "pnpm": { 32 | "overrides": { 33 | "@glimmer/component": "2.0.0" 34 | }, 35 | "peerDependencyRules": { 36 | "ignoreMissing": [ 37 | "webpack" 38 | ] 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'test-apps/*' 3 | - 'ember-scoped-css' 4 | - 'ember-scoped-css-compat' 5 | -------------------------------------------------------------------------------- /test-apps/classic-app/.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 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | indent_style = space 13 | indent_size = 2 14 | 15 | [*.hbs] 16 | insert_final_newline = false 17 | 18 | [*.{diff,md}] 19 | trim_trailing_whitespace = false 20 | -------------------------------------------------------------------------------- /test-apps/classic-app/.ember-cli: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | Ember CLI sends analytics information by default. The data is completely 4 | anonymous, but there are times when you might want to disable this behavior. 5 | 6 | Setting `disableAnalytics` to true will prevent any data from being sent. 7 | */ 8 | "disableAnalytics": false, 9 | 10 | /** 11 | Setting `isTypeScriptProject` to true will force the blueprint generators to generate TypeScript 12 | rather than JavaScript by default, when a TypeScript version of a given blueprint is available. 13 | */ 14 | "isTypeScriptProject": false 15 | } 16 | -------------------------------------------------------------------------------- /test-apps/classic-app/.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 | .eslintcache 18 | 19 | # ember-try 20 | /.node_modules.ember-try/ 21 | /bower.json.ember-try 22 | /npm-shrinkwrap.json.ember-try 23 | /package.json.ember-try 24 | /package-lock.json.ember-try 25 | /yarn.lock.ember-try 26 | -------------------------------------------------------------------------------- /test-apps/classic-app/.eslintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { configs } = require('@nullvoxpopuli/eslint-configs'); 4 | 5 | const ember = configs.ember(); 6 | 7 | // accommodates: JS, TS, App, Addon, and V2 Addon 8 | module.exports = { 9 | overrides: [...ember.overrides], 10 | }; 11 | -------------------------------------------------------------------------------- /test-apps/classic-app/.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 | /.env* 13 | /.pnp* 14 | /.sass-cache 15 | /.eslintcache 16 | /connect.lock 17 | /coverage/ 18 | /libpeerconnection.log 19 | /npm-debug.log* 20 | /testem.log 21 | /yarn-error.log 22 | 23 | # ember-try 24 | /.node_modules.ember-try/ 25 | /bower.json.ember-try 26 | /npm-shrinkwrap.json.ember-try 27 | /package.json.ember-try 28 | /package-lock.json.ember-try 29 | /yarn.lock.ember-try 30 | 31 | # broccoli-debug 32 | /DEBUG/ 33 | -------------------------------------------------------------------------------- /test-apps/classic-app/.prettierignore: -------------------------------------------------------------------------------- 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 | .eslintcache 17 | .lint-todo/ 18 | 19 | # ember-try 20 | /.node_modules.ember-try/ 21 | /bower.json.ember-try 22 | /npm-shrinkwrap.json.ember-try 23 | /package.json.ember-try 24 | /package-lock.json.ember-try 25 | /yarn.lock.ember-try 26 | *.yaml 27 | -------------------------------------------------------------------------------- /test-apps/classic-app/.prettierrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | overrides: [ 5 | { 6 | files: '*.{js,ts,cjs,mjs,mts,cts,gts.gjs}', 7 | options: { 8 | singleQuote: true, 9 | }, 10 | }, 11 | ], 12 | }; 13 | -------------------------------------------------------------------------------- /test-apps/classic-app/.template-lintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | extends: 'recommended', 5 | rules: { 6 | // we want to test this deliberately 7 | 'no-unnecessary-curly-parens': 'off', 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /test-apps/classic-app/.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": ["tmp", "dist"] 3 | } 4 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/app.js: -------------------------------------------------------------------------------- 1 | import Application from '@ember/application'; 2 | 3 | import config from 'classic-app/config/environment'; 4 | import loadInitializers from 'ember-load-initializers'; 5 | import Resolver from 'ember-resolver'; 6 | 7 | export default class App extends Application { 8 | modulePrefix = config.modulePrefix; 9 | podModulePrefix = config.podModulePrefix; 10 | Resolver = Resolver; 11 | } 12 | 13 | loadInitializers(App, config.modulePrefix); 14 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soxhub/ember-scoped-css/625bad873385b8d17e6c0b50b60d312dea5bf6a1/test-apps/classic-app/app/components/.gitkeep -------------------------------------------------------------------------------- /test-apps/classic-app/app/components/component-at-class.css: -------------------------------------------------------------------------------- 1 | .text-color { 2 | color: #0000ff !important; 3 | } 4 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/components/component-at-class.hbs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/components/dynamic-attribute.css: -------------------------------------------------------------------------------- 1 | .is-foo { 2 | color: blue; 3 | } 4 | 5 | .is-not-foo { 6 | color: red; 7 | } 8 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/components/dynamic-attribute.hbs: -------------------------------------------------------------------------------- 1 |
2 | dynamic attribute 3 |
-------------------------------------------------------------------------------- /test-apps/classic-app/app/components/face.hbs: -------------------------------------------------------------------------------- 1 |

2 | ember-css-modules 3 |

-------------------------------------------------------------------------------- /test-apps/classic-app/app/components/face.module.css: -------------------------------------------------------------------------------- 1 | .some-class { 2 | color: red; 3 | } 4 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/components/has-at-class.hbs: -------------------------------------------------------------------------------- 1 |

some text

-------------------------------------------------------------------------------- /test-apps/classic-app/app/components/header.css: -------------------------------------------------------------------------------- 1 | .test-header { 2 | color: rgb(255, 0, 0); 3 | } 4 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/components/header.hbs: -------------------------------------------------------------------------------- 1 |

2 | ember-scoped-css 3 | {{this.label}}.hbs 4 |

-------------------------------------------------------------------------------- /test-apps/classic-app/app/components/header.js: -------------------------------------------------------------------------------- 1 | import Component from '@glimmer/component'; 2 | import { tracked } from '@glimmer/tracking'; 3 | 4 | export default class Header extends Component { 5 | @tracked label = 'header'; 6 | } 7 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/components/in-app/at-class-ts/calls-has-at-class.css: -------------------------------------------------------------------------------- 1 | .text-color { 2 | color: #337 !important; 3 | } 4 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/components/in-app/at-class-ts/calls-has-at-class.gts: -------------------------------------------------------------------------------- 1 | import { scopedClass } from 'ember-scoped-css'; 2 | 3 | import HasAtClass from './has-at-class'; 4 | 5 | 8 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/components/in-app/at-class-ts/has-at-class.gts: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/components/in-app/basic.css: -------------------------------------------------------------------------------- 1 | .has-a-style { 2 | color: rgb(0, 100, 50); 3 | } 4 | 5 | div { 6 | font-weight: bold; 7 | } 8 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/components/in-app/basic.gts: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/components/in-app/misuse/no-css.hbs: -------------------------------------------------------------------------------- 1 |

No CSS here!

-------------------------------------------------------------------------------- /test-apps/classic-app/app/components/scoped.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soxhub/ember-scoped-css/625bad873385b8d17e6c0b50b60d312dea5bf6a1/test-apps/classic-app/app/components/scoped.css -------------------------------------------------------------------------------- /test-apps/classic-app/app/components/scoped.hbs: -------------------------------------------------------------------------------- 1 |
5 | Component with scoped class helper 6 |
-------------------------------------------------------------------------------- /test-apps/classic-app/app/components/show-time.css: -------------------------------------------------------------------------------- 1 | h2 { 2 | color: blue; 3 | } 4 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/components/show-time.gjs: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/components/subexpression.css: -------------------------------------------------------------------------------- 1 | .a-local-class { 2 | color: blue; 3 | } 4 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/components/subexpression.gjs: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/components/template-only.css: -------------------------------------------------------------------------------- 1 | .some-class { 2 | color: blue; 3 | } 4 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/components/template-only.hbs: -------------------------------------------------------------------------------- 1 |
hi there
-------------------------------------------------------------------------------- /test-apps/classic-app/app/controllers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soxhub/ember-scoped-css/625bad873385b8d17e6c0b50b60d312dea5bf6a1/test-apps/classic-app/app/controllers/.gitkeep -------------------------------------------------------------------------------- /test-apps/classic-app/app/controllers/application.js: -------------------------------------------------------------------------------- 1 | import Controller from '@ember/controller'; 2 | 3 | export default class ApplicationController extends Controller { 4 | time = new Date(); 5 | } 6 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soxhub/ember-scoped-css/625bad873385b8d17e6c0b50b60d312dea5bf6a1/test-apps/classic-app/app/helpers/.gitkeep -------------------------------------------------------------------------------- /test-apps/classic-app/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ClassicApp 6 | 7 | 8 | 9 | {{content-for "head"}} 10 | 11 | 12 | 17 | 18 | {{content-for "head-footer"}} 19 | 20 | 21 | {{content-for "body"}} 22 | 23 | 24 | 25 | 26 | {{content-for "body-footer"}} 27 | 28 | 29 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soxhub/ember-scoped-css/625bad873385b8d17e6c0b50b60d312dea5bf6a1/test-apps/classic-app/app/models/.gitkeep -------------------------------------------------------------------------------- /test-apps/classic-app/app/router.js: -------------------------------------------------------------------------------- 1 | import EmberRouter from '@ember/routing/router'; 2 | 3 | import config from 'classic-app/config/environment'; 4 | 5 | export default class Router extends EmberRouter { 6 | location = config.locationType; 7 | rootURL = config.rootURL; 8 | } 9 | 10 | Router.map(function () {}); 11 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/routes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soxhub/ember-scoped-css/625bad873385b8d17e6c0b50b60d312dea5bf6a1/test-apps/classic-app/app/routes/.gitkeep -------------------------------------------------------------------------------- /test-apps/classic-app/app/styles/app.css: -------------------------------------------------------------------------------- 1 | p { 2 | color: green; 3 | } 4 | 5 | .test-class-app { 6 | color: blue; 7 | } 8 | -------------------------------------------------------------------------------- /test-apps/classic-app/app/templates/application.hbs: -------------------------------------------------------------------------------- 1 | {{page-title "ClassicApp"}} 2 | 3 |

4 | {{this.time}} 5 |

6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | {{outlet}} -------------------------------------------------------------------------------- /test-apps/classic-app/config/ember-cli-update.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": "1.0.0", 3 | "packages": [ 4 | { 5 | "name": "ember-cli", 6 | "version": "4.10.0", 7 | "blueprints": [ 8 | { 9 | "name": "app", 10 | "outputRepo": "https://github.com/ember-cli/ember-new-output", 11 | "codemodsSource": "ember-app-codemods-manifest@1", 12 | "isBaseBlueprint": true, 13 | "options": ["--ci-provider=github"] 14 | } 15 | ] 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /test-apps/classic-app/config/environment.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (environment) { 4 | const ENV = { 5 | modulePrefix: 'classic-app', 6 | environment, 7 | rootURL: '/', 8 | locationType: 'history', 9 | EmberENV: { 10 | EXTEND_PROTOTYPES: false, 11 | FEATURES: { 12 | // Here you can enable experimental features on an ember canary build 13 | // e.g. EMBER_NATIVE_DECORATOR_SUPPORT: true 14 | }, 15 | }, 16 | 17 | APP: { 18 | // Here you can pass flags/options to your application instance 19 | // when it is created 20 | }, 21 | }; 22 | 23 | if (environment === 'development') { 24 | // ENV.APP.LOG_RESOLVER = true; 25 | // ENV.APP.LOG_ACTIVE_GENERATION = true; 26 | // ENV.APP.LOG_TRANSITIONS = true; 27 | // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; 28 | // ENV.APP.LOG_VIEW_LOOKUPS = true; 29 | } 30 | 31 | if (environment === 'test') { 32 | // Testem prefers this... 33 | ENV.locationType = 'none'; 34 | 35 | // keep test console output quieter 36 | ENV.APP.LOG_ACTIVE_GENERATION = false; 37 | ENV.APP.LOG_VIEW_LOOKUPS = false; 38 | 39 | ENV.APP.rootElement = '#ember-testing'; 40 | ENV.APP.autoboot = false; 41 | } 42 | 43 | if (environment === 'production') { 44 | // here you can enable a production-specific feature 45 | } 46 | 47 | return ENV; 48 | }; 49 | -------------------------------------------------------------------------------- /test-apps/classic-app/config/optional-features.json: -------------------------------------------------------------------------------- 1 | { 2 | "application-template-wrapper": false, 3 | "default-async-observers": true, 4 | "jquery-integration": false, 5 | "template-only-glimmer-components": true 6 | } 7 | -------------------------------------------------------------------------------- /test-apps/classic-app/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 | module.exports = { 10 | browsers, 11 | }; 12 | -------------------------------------------------------------------------------- /test-apps/classic-app/ember-cli-build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const EmberApp = require('ember-cli/lib/broccoli/ember-app'); 4 | 5 | module.exports = function (defaults) { 6 | const app = new EmberApp(defaults, { 7 | // Add options here 8 | cssModules: { 9 | extension: 'module.css', 10 | }, 11 | 'ember-cli-babel': { 12 | enableTypeScriptTransform: true, 13 | }, 14 | 'ember-scoped-css': { 15 | layerName: 'classic-app-layer', 16 | }, 17 | }); 18 | 19 | // Use `app.import` to add additional libraries to the generated 20 | // output files. 21 | // 22 | // If you need to use different assets in different 23 | // environments, specify an object as the first parameter. That 24 | // object's keys should be the environment name and the values 25 | // should be the asset to use in that environment. 26 | // 27 | // If the library that you are including contains AMD or ES6 28 | // modules that you would like to import into your application 29 | // please specify an object with the list of modules as keys 30 | // along with the exports of each module as its value. 31 | 32 | app.import('node_modules/v2-addon/dist/scoped.css'); 33 | 34 | return app.toTree(); 35 | }; 36 | -------------------------------------------------------------------------------- /test-apps/classic-app/public/robots.txt: -------------------------------------------------------------------------------- 1 | # http://www.robotstxt.org 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /test-apps/classic-app/testem.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | test_page: 'tests/index.html?hidepassed', 5 | disable_watching: true, 6 | launch_in_ci: ['Chrome'], 7 | launch_in_dev: ['Chrome'], 8 | browser_start_timeout: 120, 9 | browser_args: { 10 | Chrome: { 11 | ci: [ 12 | // --no-sandbox is needed when running Chrome inside a container 13 | process.env.CI ? '--no-sandbox' : null, 14 | '--headless', 15 | '--disable-dev-shm-usage', 16 | '--disable-software-rasterizer', 17 | '--mute-audio', 18 | '--remote-debugging-port=0', 19 | '--window-size=1440,900', 20 | ].filter(Boolean), 21 | }, 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /test-apps/classic-app/tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ClassicApp Tests 6 | 7 | 8 | 9 | {{content-for "head"}} {{content-for "test-head"}} 10 | 11 | 12 | 13 | 14 | 15 | {{content-for "head-footer"}} {{content-for "test-head-footer"}} 16 | 17 | 18 | {{content-for "body"}} {{content-for "test-body"}} 19 | 20 |
21 |
22 |
23 |
24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | {{content-for "body-footer"}} {{content-for "test-body-footer"}} 34 | 35 | 36 | -------------------------------------------------------------------------------- /test-apps/classic-app/tests/shared-scenarios/from-v2-addon-ts/at-class-test.gjs: -------------------------------------------------------------------------------- 1 | 2 | import { render } from '@ember/test-helpers'; 3 | import { hbs } from 'ember-cli-htmlbars'; 4 | import { module, test } from 'qunit'; 5 | import { setupRenderingTest } from 'ember-qunit'; 6 | 7 | import ComponentAtClass from 'v2-addon-ts/components/at-class-ts/component-at-class'; 8 | 9 | import { scopedClass } from 'ember-scoped-css/test-support'; 10 | 11 | 12 | module('[v2 Addon TS] Integration | Component | @class', function (hooks) { 13 | setupRenderingTest(hooks); 14 | 15 | test('strict mode', async function (assert) { 16 | await render( 19 | ); 20 | 21 | assert 22 | .dom('p') 23 | .hasClass( 24 | scopedClass('text-color', 'v2-addon-ts/components/at-class-ts/component-at-class') 25 | ); 26 | assert.dom('p').hasStyle({ color: 'rgb(0, 0, 255)' }); 27 | }); 28 | 29 | test('loose mode', async function (assert) { 30 | await render(hbs` 31 | 32 | `); 33 | 34 | assert 35 | .dom('p') 36 | .hasClass( 37 | scopedClass('text-color', 'v2-addon-ts/components/at-class-ts/component-at-class') 38 | ); 39 | assert.dom('p').hasStyle({ color: 'rgb(0, 0, 255)' }); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /test-apps/classic-app/tests/shared-scenarios/from-v2-addon-ts/strict-class-test.gjs: -------------------------------------------------------------------------------- 1 | import { render } from '@ember/test-helpers'; 2 | import { module, test } from 'qunit'; 3 | import { setupRenderingTest } from 'ember-qunit'; 4 | 5 | import { StrictClass } from 'v2-addon-ts/components/strict-class'; 6 | 7 | import { scopedClass } from 'ember-scoped-css/test-support'; 8 | 9 | module('[v2 Addon TS] Integration | Component | Strict class import', function (hooks) { 10 | setupRenderingTest(hooks); 11 | 12 | test('strict mode', async function (assert) { 13 | await render( 16 | ); 17 | 18 | assert 19 | .dom('div') 20 | .hasClass( 21 | scopedClass('hello-there', 'v2-addon-ts/components/strict-class') 22 | ); 23 | assert.dom('div').hasStyle({ color: 'rgb(1, 2, 3)' }); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test-apps/classic-app/tests/shared-scenarios/from-v2-addon-ts/strict-test.gjs: -------------------------------------------------------------------------------- 1 | import { render } from '@ember/test-helpers'; 2 | import { module, test } from 'qunit'; 3 | import { setupRenderingTest } from 'ember-qunit'; 4 | 5 | import { Strict } from 'v2-addon-ts/components/strict'; 6 | 7 | import { scopedClass } from 'ember-scoped-css/test-support'; 8 | 9 | module('[v2 Addon TS] Integration | Component | Strict import', function (hooks) { 10 | setupRenderingTest(hooks); 11 | 12 | test('strict mode', async function (assert) { 13 | await render( 16 | ); 17 | 18 | assert 19 | .dom('p') 20 | .hasClass( 21 | scopedClass('hi', 'v2-addon-ts/components/strict') 22 | ); 23 | assert.dom('p').hasStyle({ color: 'rgb(0, 0, 255)' }); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test-apps/classic-app/tests/shared-scenarios/from-v2-addon-ts/v2-addon-ts-with-a-class-test.js: -------------------------------------------------------------------------------- 1 | import { render } from '@ember/test-helpers'; 2 | import { hbs } from 'ember-cli-htmlbars'; 3 | import { module, test } from 'qunit'; 4 | import { setupRenderingTest } from 'ember-qunit'; 5 | 6 | import { scopedClass } from 'ember-scoped-css/test-support'; 7 | 8 | module( 9 | '[v2 Addon TS] Integration | Component | WithAClass from v2-addon-ts', 10 | function (hooks) { 11 | setupRenderingTest(hooks); 12 | 13 | test('it has scoped class', async function (assert) { 14 | await render(hbs``); 15 | 16 | assert.dom('div').hasClass('greeting_efc49be66'); 17 | assert.dom('div').hasStyle({ color: 'rgb(0, 0, 255)' }); 18 | assert 19 | .dom('div') 20 | .hasClass( 21 | scopedClass('greeting', 'v2-addon-ts/components/with-a-class'), 22 | ); 23 | }); 24 | }, 25 | ); 26 | -------------------------------------------------------------------------------- /test-apps/classic-app/tests/shared-scenarios/from-v2-addon/alert-from-v2-addon-test.js: -------------------------------------------------------------------------------- 1 | import { render } from '@ember/test-helpers'; 2 | import { hbs } from 'ember-cli-htmlbars'; 3 | import { module, test } from 'qunit'; 4 | import { setupRenderingTest } from 'ember-qunit'; 5 | 6 | import { scopedClass } from 'ember-scoped-css/test-support'; 7 | 8 | module( 9 | '[v2 Addon JS] Integration | Component | Alert from v2-addon', 10 | function (hooks) { 11 | setupRenderingTest(hooks); 12 | 13 | test('it has scoped class', async function (assert) { 14 | await render(hbs``); 15 | 16 | assert.dom('p').hasClass('message_e4b9579df'); 17 | assert.dom('p').hasStyle({ fontStyle: 'italic' }); 18 | assert 19 | .dom('p') 20 | .hasClass(scopedClass('message', 'v2-addon/components/alert')); 21 | }); 22 | }, 23 | ); 24 | -------------------------------------------------------------------------------- /test-apps/classic-app/tests/shared-scenarios/from-v2-addon/at-class-test.gjs: -------------------------------------------------------------------------------- 1 | 2 | import { render } from '@ember/test-helpers'; 3 | import { hbs } from 'ember-cli-htmlbars'; 4 | import { module, test } from 'qunit'; 5 | import { setupRenderingTest } from 'ember-qunit'; 6 | 7 | import ComponentAtClass from 'v2-addon/components/at-class/component-at-class'; 8 | 9 | import { scopedClass } from 'ember-scoped-css/test-support'; 10 | 11 | 12 | module('[v2 Addon JS] Integration | Component | @class', function (hooks) { 13 | setupRenderingTest(hooks); 14 | 15 | test('strict mode', async function (assert) { 16 | await render( 19 | ); 20 | 21 | assert 22 | .dom('p') 23 | .hasClass( 24 | scopedClass('text-color', 'v2-addon/components/at-class/component-at-class') 25 | ); 26 | assert.dom('p').hasStyle({ color: 'rgb(0, 0, 255)' }); 27 | }); 28 | 29 | test('loose mode', async function (assert) { 30 | await render(hbs` 31 | 32 | `); 33 | 34 | assert 35 | .dom('p') 36 | .hasClass( 37 | scopedClass('text-color', 'v2-addon/components/at-class/component-at-class') 38 | ); 39 | assert.dom('p').hasStyle({ color: 'rgb(0, 0, 255)' }); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /test-apps/classic-app/tests/shared-scenarios/in-app/at-class-test.gts: -------------------------------------------------------------------------------- 1 | import { render } from '@ember/test-helpers'; 2 | import { module, test } from 'qunit'; 3 | import { setupRenderingTest } from 'ember-qunit'; 4 | 5 | import CallsAtHasClass from 'classic-app/components/in-app/at-class-ts/calls-has-at-class'; 6 | 7 | import { scopedClass } from 'ember-scoped-css/test-support'; 8 | 9 | module('[In App] at-class-ts', function(hooks) { 10 | setupRenderingTest(hooks); 11 | 12 | test('calls component with @class', async function(assert) { 13 | await render( 14 | 17 | ); 18 | 19 | assert.dom('p').hasClass('text-color_ed46c3a30'); 20 | assert.dom('p').hasClass(scopedClass('text-color', 'classic-app/components/in-app/at-class-ts/calls-has-at-class')); 21 | assert.dom('p').hasStyle({ color: 'rgb(51, 51, 119)' }); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test-apps/classic-app/tests/shared-scenarios/in-app/basic-test.gts: -------------------------------------------------------------------------------- 1 | import { render } from '@ember/test-helpers'; 2 | import { module, test } from 'qunit'; 3 | import { setupRenderingTest } from 'ember-qunit'; 4 | 5 | import Basic from 'classic-app/components/in-app/basic'; 6 | 7 | import { scopedClass } from 'ember-scoped-css/test-support'; 8 | 9 | module('[In App] basic', function(hooks) { 10 | setupRenderingTest(hooks); 11 | 12 | test('has a style on an element', async function(assert) { 13 | await render( 14 | 17 | ); 18 | 19 | assert.dom('div').hasClass('has-a-style_e8d85123f'); 20 | assert.dom('div').hasClass(scopedClass('has-a-style', 'classic-app/components/in-app/basic')); 21 | assert.dom('div').hasStyle({ color: 'rgb(0, 100, 50)', fontWeight: '700' }); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test-apps/classic-app/tests/shared-scenarios/in-app/component-at-class-test.gjs: -------------------------------------------------------------------------------- 1 | import { render } from '@ember/test-helpers'; 2 | import { hbs } from 'ember-cli-htmlbars'; 3 | import { module, test } from 'qunit'; 4 | import { setupRenderingTest } from 'ember-qunit'; 5 | 6 | import ComponentAtClass from 'classic-app/components/component-at-class'; 7 | 8 | import { scopedClass } from 'ember-scoped-css/test-support'; 9 | 10 | 11 | module('[In App] @class', function (hooks) { 12 | setupRenderingTest(hooks); 13 | 14 | test('strict mode', async function (assert) { 15 | await render( 18 | ); 19 | 20 | assert 21 | .dom('p') 22 | .hasClass( 23 | scopedClass('text-color', 'classic-app/components/component-at-class') 24 | ); 25 | assert.dom('p').hasStyle({ color: 'rgb(0, 0, 255)' }); 26 | }); 27 | 28 | test('loose mode', async function (assert) { 29 | await render(hbs` 30 | 31 | `); 32 | 33 | assert 34 | .dom('p') 35 | .hasClass( 36 | scopedClass('text-color', 'classic-app/components/component-at-class') 37 | ); 38 | assert.dom('p').hasStyle({ color: 'rgb(0, 0, 255)' }); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /test-apps/classic-app/tests/shared-scenarios/in-app/dynamic-attribute-test.js: -------------------------------------------------------------------------------- 1 | import { tracked } from '@glimmer/tracking'; 2 | import { render, settled } from '@ember/test-helpers'; 3 | import { hbs } from 'ember-cli-htmlbars'; 4 | import { module, test } from 'qunit'; 5 | import { setupRenderingTest } from 'ember-qunit'; 6 | 7 | module('[In App] DynamicAttribute', function (hooks) { 8 | setupRenderingTest(hooks); 9 | 10 | test('it has scoped class', async function (assert) { 11 | class State { 12 | @tracked ya = true; 13 | } 14 | 15 | let state = new State(); 16 | 17 | this.setProperties({ state }); 18 | await render(hbs``); 19 | 20 | assert.dom('div').hasClass('is-foo_e3cf3bd44'); 21 | assert.dom('div').hasStyle({ color: 'rgb(0, 0, 255)' }); 22 | 23 | state.ya = false; 24 | await settled(); 25 | 26 | assert.dom('div').hasClass('is-not-foo_e3cf3bd44'); 27 | assert.dom('div').hasStyle({ color: 'rgb(255, 0, 0)' }); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /test-apps/classic-app/tests/shared-scenarios/in-app/header-test.js: -------------------------------------------------------------------------------- 1 | import { render } from '@ember/test-helpers'; 2 | import { hbs } from 'ember-cli-htmlbars'; 3 | import { module, test } from 'qunit'; 4 | import { setupRenderingTest } from 'ember-qunit'; 5 | 6 | import { scopedClass } from 'ember-scoped-css/test-support'; 7 | 8 | module('[In App] header', function (hooks) { 9 | setupRenderingTest(hooks); 10 | 11 | test('it has scoped class', async function (assert) { 12 | await render(hbs`
`); 13 | 14 | assert.dom('h1').hasClass('test-header_e64a12152'); 15 | assert.dom('h1').hasStyle({ color: 'rgb(255, 0, 0)' }); 16 | assert 17 | .dom('h1') 18 | .hasClass(scopedClass('test-header', 'classic-app/components/header')); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /test-apps/classic-app/tests/shared-scenarios/in-app/misuse-test.js: -------------------------------------------------------------------------------- 1 | import { render } from '@ember/test-helpers'; 2 | import { hbs } from 'ember-cli-htmlbars'; 3 | import { module, skip } from 'qunit'; 4 | import { setupRenderingTest } from 'ember-qunit'; 5 | 6 | module('[In App] Misuse', function (hooks) { 7 | setupRenderingTest(hooks); 8 | 9 | skip('it has scoped class', async function () { 10 | // Errors (intentional, but we can't catch it) 11 | // https://github.com/qunitjs/qunit/issues/1736 12 | await render(hbs``); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /test-apps/classic-app/tests/shared-scenarios/in-app/scoped-test.js: -------------------------------------------------------------------------------- 1 | import { render } from '@ember/test-helpers'; 2 | import { hbs } from 'ember-cli-htmlbars'; 3 | import { module, test } from 'qunit'; 4 | import { setupRenderingTest } from 'ember-qunit'; 5 | 6 | module('[In App] scoped', function (hooks) { 7 | setupRenderingTest(hooks); 8 | 9 | test('it replaces the scoped-class helper', async function (assert) { 10 | await render(hbs``); 11 | 12 | assert.dom('div').hasAttribute('data-scoped-class', 'some-class_e4aeedfc0'); 13 | assert 14 | .dom('div') 15 | .hasAttribute('data-scoped-class-2', 'some-class-2_e4aeedfc0'); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /test-apps/classic-app/tests/shared-scenarios/in-app/show-time-test.js: -------------------------------------------------------------------------------- 1 | import { render } from '@ember/test-helpers'; 2 | import { hbs } from 'ember-cli-htmlbars'; 3 | import { module, test } from 'qunit'; 4 | import { setupRenderingTest } from 'ember-qunit'; 5 | 6 | module('[In App] show-time', function (hooks) { 7 | setupRenderingTest(hooks); 8 | 9 | test('it has scoped class', async function (assert) { 10 | await render(hbs``); 11 | 12 | assert.dom('h2').hasClass('e6e05c2f6'); 13 | assert.dom('h2').hasStyle({ color: 'rgb(0, 0, 255)' }); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /test-apps/classic-app/tests/shared-scenarios/in-app/subexpression-test.gjs: -------------------------------------------------------------------------------- 1 | import { render, settled } from '@ember/test-helpers'; 2 | import { module, test } from 'qunit'; 3 | import { setupRenderingTest } from 'ember-qunit'; 4 | 5 | import SubExpression from 'classic-app/components/subexpression'; 6 | import { cell } from 'ember-resources'; 7 | 8 | import { scopedClass } from 'ember-scoped-css/test-support'; 9 | 10 | module('[In App] subexpression', function (hooks) { 11 | setupRenderingTest(hooks); 12 | 13 | test('it has scoped class', async function (assert) { 14 | let cond = cell(false); 15 | 16 | await render( 19 | ); 20 | 21 | assert.dom('div').hasClass('global-probably'); 22 | 23 | cond.current = true; 24 | await settled(); 25 | 26 | 27 | assert 28 | .dom('div') 29 | .hasClass( 30 | scopedClass('a-local-class', 'classic-app/components/subexpression') 31 | ); 32 | assert.dom('div').hasStyle({ color: 'rgb(0, 0, 255)' }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /test-apps/classic-app/tests/shared-scenarios/in-app/template-only-test.js: -------------------------------------------------------------------------------- 1 | import { render } from '@ember/test-helpers'; 2 | import { hbs } from 'ember-cli-htmlbars'; 3 | import { module, test } from 'qunit'; 4 | import { setupRenderingTest } from 'ember-qunit'; 5 | 6 | import { scopedClass } from 'ember-scoped-css/test-support'; 7 | 8 | module('[In App] template-only', function (hooks) { 9 | setupRenderingTest(hooks); 10 | 11 | test('it has scoped class', async function (assert) { 12 | await render(hbs``); 13 | 14 | assert 15 | .dom('div') 16 | .hasClass( 17 | scopedClass('some-class', 'classic-app/components/template-only'), 18 | ); 19 | assert.dom('div').hasStyle({ color: 'rgb(0, 0, 255)' }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test-apps/classic-app/tests/test-helper.js: -------------------------------------------------------------------------------- 1 | import { setApplication } from '@ember/test-helpers'; 2 | import * as QUnit from 'qunit'; 3 | import { setup } from 'qunit-dom'; 4 | import { start } from 'ember-qunit'; 5 | 6 | import Application from 'classic-app/app'; 7 | import config from 'classic-app/config/environment'; 8 | 9 | setApplication(Application.create(config.APP)); 10 | 11 | setup(QUnit.assert); 12 | 13 | start(); 14 | -------------------------------------------------------------------------------- /test-apps/embroider-app/.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 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | indent_style = space 13 | indent_size = 2 14 | 15 | [*.hbs] 16 | insert_final_newline = false 17 | 18 | [*.{diff,md}] 19 | trim_trailing_whitespace = false 20 | -------------------------------------------------------------------------------- /test-apps/embroider-app/.ember-cli: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | Ember CLI sends analytics information by default. The data is completely 4 | anonymous, but there are times when you might want to disable this behavior. 5 | 6 | Setting `disableAnalytics` to true will prevent any data from being sent. 7 | */ 8 | "disableAnalytics": false, 9 | 10 | /** 11 | Setting `isTypeScriptProject` to true will force the blueprint generators to generate TypeScript 12 | rather than JavaScript by default, when a TypeScript version of a given blueprint is available. 13 | */ 14 | "isTypeScriptProject": false, 15 | "port": 4201 16 | } 17 | -------------------------------------------------------------------------------- /test-apps/embroider-app/.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 | .eslintcache 18 | 19 | # ember-try 20 | /.node_modules.ember-try/ 21 | /bower.json.ember-try 22 | /npm-shrinkwrap.json.ember-try 23 | /package.json.ember-try 24 | /package-lock.json.ember-try 25 | /yarn.lock.ember-try 26 | -------------------------------------------------------------------------------- /test-apps/embroider-app/.eslintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { configs } = require('@nullvoxpopuli/eslint-configs'); 4 | 5 | const ember = configs.ember(); 6 | 7 | // accommodates: JS, TS, App, Addon, and V2 Addon 8 | module.exports = { 9 | overrides: [...ember.overrides], 10 | }; 11 | -------------------------------------------------------------------------------- /test-apps/embroider-app/.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 | /.env* 13 | /.pnp* 14 | /.sass-cache 15 | /.eslintcache 16 | /connect.lock 17 | /coverage/ 18 | /libpeerconnection.log 19 | /npm-debug.log* 20 | /testem.log 21 | /yarn-error.log 22 | 23 | # ember-try 24 | /.node_modules.ember-try/ 25 | /bower.json.ember-try 26 | /npm-shrinkwrap.json.ember-try 27 | /package.json.ember-try 28 | /package-lock.json.ember-try 29 | /yarn.lock.ember-try 30 | 31 | # broccoli-debug 32 | /DEBUG/ 33 | -------------------------------------------------------------------------------- /test-apps/embroider-app/.prettierignore: -------------------------------------------------------------------------------- 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 | .eslintcache 17 | .lint-todo/ 18 | 19 | # ember-try 20 | /.node_modules.ember-try/ 21 | /bower.json.ember-try 22 | /npm-shrinkwrap.json.ember-try 23 | /package.json.ember-try 24 | /package-lock.json.ember-try 25 | /yarn.lock.ember-try 26 | *.yaml 27 | -------------------------------------------------------------------------------- /test-apps/embroider-app/.prettierrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | overrides: [ 5 | { 6 | files: '*.{js,ts,cjs,mjs,mts,cts,gts.gjs}', 7 | options: { 8 | singleQuote: true, 9 | }, 10 | }, 11 | ], 12 | }; 13 | -------------------------------------------------------------------------------- /test-apps/embroider-app/.template-lintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | extends: 'recommended', 5 | }; 6 | -------------------------------------------------------------------------------- /test-apps/embroider-app/.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": ["tmp", "dist"] 3 | } 4 | -------------------------------------------------------------------------------- /test-apps/embroider-app/app/app.js: -------------------------------------------------------------------------------- 1 | import Application from '@ember/application'; 2 | 3 | import loadInitializers from 'ember-load-initializers'; 4 | import Resolver from 'ember-resolver'; 5 | import config from 'embroider-app/config/environment'; 6 | 7 | export default class App extends Application { 8 | modulePrefix = config.modulePrefix; 9 | podModulePrefix = config.podModulePrefix; 10 | Resolver = Resolver; 11 | } 12 | 13 | loadInitializers(App, config.modulePrefix); 14 | -------------------------------------------------------------------------------- /test-apps/embroider-app/app/components/forth.css: -------------------------------------------------------------------------------- 1 | div { 2 | width: 250px; 3 | border: 1px solid black; 4 | padding: 0px 15px; 5 | margin-top: 15px; 6 | } 7 | 8 | .header { 9 | margin-top: 0; 10 | background-color: lightslategrey; 11 | padding: 15px; 12 | margin: 0px -15px; 13 | text-align: right; 14 | } 15 | 16 | .message { 17 | font-weight: bold; 18 | font-size: 3em; 19 | } 20 | -------------------------------------------------------------------------------- /test-apps/embroider-app/app/components/forth.gjs: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /test-apps/embroider-app/app/components/in-app/at-class-ts/calls-has-at-class.css: -------------------------------------------------------------------------------- 1 | .text-color { 2 | color: #337 !important; 3 | } 4 | -------------------------------------------------------------------------------- /test-apps/embroider-app/app/components/in-app/at-class-ts/calls-has-at-class.gts: -------------------------------------------------------------------------------- 1 | import { scopedClass } from 'ember-scoped-css'; 2 | 3 | import HasAtClass from './has-at-class'; 4 | 5 | 8 | -------------------------------------------------------------------------------- /test-apps/embroider-app/app/components/in-app/at-class-ts/has-at-class.gts: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /test-apps/embroider-app/app/components/in-app/basic.css: -------------------------------------------------------------------------------- 1 | .has-a-style { 2 | color: rgb(0, 100, 50); 3 | } 4 | 5 | div { 6 | font-weight: bold; 7 | } 8 | -------------------------------------------------------------------------------- /test-apps/embroider-app/app/components/in-app/basic.gts: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /test-apps/embroider-app/app/components/in-app/misuse/no-css.hbs: -------------------------------------------------------------------------------- 1 |

No CSS here!

-------------------------------------------------------------------------------- /test-apps/embroider-app/app/components/my-component.css: -------------------------------------------------------------------------------- 1 | div { 2 | width: 300px; 3 | border: 1px solid black; 4 | border-radius: 4px; 5 | padding: 0px 15px; 6 | margin-top: 15px; 7 | } 8 | 9 | .header { 10 | margin-top: 0; 11 | background-color: lightblue; 12 | border-top-left-radius: 4px; 13 | border-top-right-radius: 4px; 14 | padding: 15px; 15 | margin: 0px -15px; 16 | color: rgb(255, 0, 0); 17 | } 18 | 19 | .message { 20 | font-style: italic; 21 | font-size: 2em; 22 | } 23 | -------------------------------------------------------------------------------- /test-apps/embroider-app/app/components/my-component.hbs: -------------------------------------------------------------------------------- 1 |
2 |

3 | {{@title}} 4 |

5 |

6 | {{@message}} 7 |

8 | {{yield}} 9 |
-------------------------------------------------------------------------------- /test-apps/embroider-app/app/components/second.css: -------------------------------------------------------------------------------- 1 | div { 2 | width: 220px; 3 | border: 1px solid black; 4 | padding: 0px 15px; 5 | margin-top: 15px; 6 | } 7 | 8 | .header { 9 | margin-top: 0; 10 | background-color: lightcoral; 11 | padding: 15px; 12 | margin: 0px -15px; 13 | } 14 | 15 | .message { 16 | font-style: italic; 17 | font-size: 1em; 18 | } 19 | -------------------------------------------------------------------------------- /test-apps/embroider-app/app/components/second.hbs: -------------------------------------------------------------------------------- 1 |
2 |

3 | {{@title}} 4 |

5 |

6 | {{@message}} 7 |

8 |
-------------------------------------------------------------------------------- /test-apps/embroider-app/app/components/template-only.css: -------------------------------------------------------------------------------- 1 | .some-class { 2 | color: blue; 3 | } 4 | -------------------------------------------------------------------------------- /test-apps/embroider-app/app/components/template-only.hbs: -------------------------------------------------------------------------------- 1 |
hi there
-------------------------------------------------------------------------------- /test-apps/embroider-app/app/components/third.gjs: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /test-apps/embroider-app/app/components/with-class.gjs: -------------------------------------------------------------------------------- 1 | 2 | import Component from '@glimmer/component'; 3 | 4 | export default class Hello extends Component { 5 | name = 'world'; 6 | 7 | 18 | } 19 | 20 | -------------------------------------------------------------------------------- /test-apps/embroider-app/app/controllers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soxhub/ember-scoped-css/625bad873385b8d17e6c0b50b60d312dea5bf6a1/test-apps/embroider-app/app/controllers/.gitkeep -------------------------------------------------------------------------------- /test-apps/embroider-app/app/controllers/application.js: -------------------------------------------------------------------------------- 1 | import Controller from '@ember/controller'; 2 | 3 | export default class ApplicationController extends Controller { 4 | time = new Date(); 5 | } 6 | -------------------------------------------------------------------------------- /test-apps/embroider-app/app/helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soxhub/ember-scoped-css/625bad873385b8d17e6c0b50b60d312dea5bf6a1/test-apps/embroider-app/app/helpers/.gitkeep -------------------------------------------------------------------------------- /test-apps/embroider-app/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | TestApp 6 | 7 | 8 | 9 | {{content-for "head"}} 10 | 11 | 12 | 17 | 18 | {{content-for "head-footer"}} 19 | 20 | 21 | {{content-for "body"}} 22 | 23 | 24 | 25 | 26 | {{content-for "body-footer"}} 27 | 28 | 29 | -------------------------------------------------------------------------------- /test-apps/embroider-app/app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soxhub/ember-scoped-css/625bad873385b8d17e6c0b50b60d312dea5bf6a1/test-apps/embroider-app/app/models/.gitkeep -------------------------------------------------------------------------------- /test-apps/embroider-app/app/router.js: -------------------------------------------------------------------------------- 1 | import EmberRouter from '@ember/routing/router'; 2 | 3 | import config from 'embroider-app/config/environment'; 4 | 5 | export default class Router extends EmberRouter { 6 | location = config.locationType; 7 | rootURL = config.rootURL; 8 | } 9 | 10 | Router.map(function () {}); 11 | -------------------------------------------------------------------------------- /test-apps/embroider-app/app/routes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soxhub/ember-scoped-css/625bad873385b8d17e6c0b50b60d312dea5bf6a1/test-apps/embroider-app/app/routes/.gitkeep -------------------------------------------------------------------------------- /test-apps/embroider-app/app/styles/app.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soxhub/ember-scoped-css/625bad873385b8d17e6c0b50b60d312dea5bf6a1/test-apps/embroider-app/app/styles/app.css -------------------------------------------------------------------------------- /test-apps/embroider-app/app/templates/application.css: -------------------------------------------------------------------------------- 1 | h3 { 2 | color: #00ff00; 3 | background-color: transparent; 4 | } 5 | -------------------------------------------------------------------------------- /test-apps/embroider-app/app/templates/application.hbs: -------------------------------------------------------------------------------- 1 | {{page-title "TestEmbroiderCssLayers"}} 2 |

3 | Scoped css on route. 4 | {{this.time}} 5 |

6 |
7 |