├── .editorconfig ├── .eslintrc.json ├── .github └── dependabot.yml ├── .gitignore ├── .husky ├── .gitignore ├── commit-msg └── pre-commit ├── .nycrc.json ├── .prettierrc ├── .releaserc ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── babel.config.js ├── commitlint.config.js ├── dist ├── defaults.d.ts ├── index.d.ts ├── index.esm.js ├── index.esm.js.map ├── index.js ├── index.js.map ├── index.modern.js ├── index.modern.js.map ├── index.modern.mjs ├── index.modern.mjs.map ├── index.umd.js ├── index.umd.js.map ├── lib │ └── validation.d.ts └── unsafe-quiet-stylelint-deprecation-warning.d.ts ├── docs ├── .nojekyll ├── README.md ├── interfaces │ ├── defaults.declarationstrictvalueresult.md │ ├── defaults.ignorevaluehash.md │ ├── defaults.ignorevariableorfunctionhash.md │ └── defaults.secondaryoptions.md └── modules │ ├── defaults.md │ ├── index.md │ ├── index.rule.md │ └── lib_validation.md ├── jest.config.json ├── jest.coverage.config.js ├── jest.setup.js ├── lint-staged.config.js ├── package-lock.json ├── package.json ├── src ├── defaults.ts ├── index.ts ├── lib │ └── validation.ts └── unsafe-quiet-stylelint-deprecation-warning.ts ├── test ├── .eslintrc.json ├── auto-fix-func.js ├── custom-message.js ├── default.js ├── helpers │ ├── auto-fix-func-with-throw.js │ └── auto-fix-func.js ├── ignore-functions.js ├── ignore-unlisted-properties.js ├── ignore-variables.js ├── keywords-hash.js ├── multiple-keywords.js ├── multiple-properties.js ├── multiple-values.js ├── regex-property.js ├── severity.js ├── shorthand.js ├── single-keyword.js ├── single-value.js ├── skip-var-defs.js ├── unsafe-quiet-stylelint-deprecation-warning.js └── values-hash.js ├── tsconfig.build.json ├── tsconfig.json ├── typedoc.json └── types ├── css-values.d.ts └── shortcss.d.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [**] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | insert_final_newline = true -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["airbnb-typescript/base", "plugin:@typescript-eslint/recommended", "prettier", "plugin:prettier/recommended"], 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 2020, 6 | "sourceType": "module", 7 | "ecmaFeatures": { 8 | "experimentalObjectRestSpread": true, 9 | "classes": true 10 | }, 11 | "project": "./tsconfig.json" 12 | }, 13 | "plugins": [ 14 | "@typescript-eslint", 15 | "eslint-plugin-tsdoc" 16 | ], 17 | "rules": { 18 | "dot-notation": "off", 19 | "max-len": ["warn", { "ignoreComments": true, "code": 140, "tabWidth": 2 }], 20 | "no-cond-assign": ["error", "except-parens"], 21 | "no-else-return": "warn", 22 | "no-use-before-define": "off", 23 | "@typescript-eslint/no-use-before-define": ["error", { "functions": false, "classes": false }], 24 | "@typescript-eslint/no-non-null-assertion": "off", 25 | "tsdoc/syntax": "warn", 26 | "camelcase": "off", 27 | "@typescript-eslint/naming-convention": [ 28 | "error", 29 | { 30 | "selector": "default", 31 | "format": ["camelCase"] 32 | }, 33 | 34 | { 35 | "selector": "variable", 36 | "format": ["camelCase", "UPPER_CASE"] 37 | }, 38 | { 39 | "selector": "parameter", 40 | "format": ["camelCase"], 41 | "leadingUnderscore": "allow" 42 | }, 43 | 44 | { 45 | "selector": "memberLike", 46 | "modifiers": ["private"], 47 | "format": ["camelCase"], 48 | "leadingUnderscore": "require" 49 | }, 50 | 51 | { 52 | "selector": "typeLike", 53 | "format": ["PascalCase"] 54 | }, 55 | 56 | { 57 | "selector": "interface", 58 | "format": ["PascalCase"], 59 | "custom": { 60 | "regex": "^I[A-Z]", 61 | "match": false 62 | } 63 | }, 64 | 65 | { 66 | "selector": "typeAlias", 67 | "format": ["PascalCase"], 68 | "custom": { 69 | "regex": "^T[A-Z]", 70 | "match": false 71 | } 72 | } 73 | ] 74 | }, 75 | "globals": {} 76 | } 77 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | ignore: 9 | - dependency-name: "@commitlint/config-conventional" 10 | versions: 11 | - 12.0.0 12 | - dependency-name: "@commitlint/cli" 13 | versions: 14 | - 12.0.0 15 | - dependency-name: husky 16 | versions: 17 | - 5.0.9 18 | - 5.1.0 19 | - dependency-name: eslint-config-prettier 20 | versions: 21 | - 8.0.0 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | .env 4 | .nyc_output 5 | .rts2_cache_* 6 | /node_modules/ 7 | /coverage/ 8 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx --no-install commitlint --edit $1 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx --no-install lint-staged 5 | -------------------------------------------------------------------------------- /.nycrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": [ 3 | "babel-register-ts" 4 | ], 5 | "all": true, 6 | "exclude": ["node_modules", "**/coverage/**", "commitlint.config.js", "test", "lint-staged.config.js"], 7 | "include": ["src/**/*"], 8 | "check-coverage": true, 9 | "per-file": true, 10 | "branches": 85, 11 | "lines": 85, 12 | "functions": 85, 13 | "statements": 85 14 | } 15 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 2, 4 | "semi": true, 5 | "singleQuote": true, 6 | "bracketSpacing": true, 7 | "arrowParens": "always", 8 | "endOfLine": "lf" 9 | } 10 | -------------------------------------------------------------------------------- /.releaserc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["@semantic-release/commit-analyzer", { 4 | "preset": "angular", 5 | "releaseRules": [ 6 | { "type": "refactor", "release": "patch" }, 7 | { "type": "docs", "release": "patch" } 8 | ], 9 | "parserOpts": { 10 | "noteKeywords": ["BREAKING CHANGE", "BREAKING CHANGES"] 11 | } 12 | }], 13 | "@semantic-release/release-notes-generator", 14 | ["@semantic-release/changelog", { 15 | "changelogFile": "CHANGELOG.md" 16 | }], 17 | ["@semantic-release/npm", { 18 | "npmPublish": true 19 | }], 20 | ["@semantic-release/exec", { 21 | "prepareCmd": "npm run build && npm run docs" 22 | }], 23 | ["@semantic-release/git", { 24 | "assets": ["dist", "docs", "CHANGELOG.md", "API.md", "README.md", "package.json", "package-lock.json"], 25 | "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" 26 | }], 27 | ["@semantic-release/exec", { 28 | "prepareCmd": "git push && git push --tags" 29 | }] 30 | ], 31 | "branch": "master", 32 | "dryRun": false, 33 | "ci": false 34 | } 35 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | git: 2 | depth: 3 3 | language: node_js 4 | node_js: 5 | - "node" 6 | install: 7 | - npm install 8 | before_script: 9 | - npm run eslint 10 | - npm run test 11 | - npm run coverage 12 | script: 13 | - npm run build 14 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [1.10.11](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.10.10...v1.10.11) (2025-03-09) 2 | 3 | 4 | ### Reverts 5 | 6 | * Revert "fix: exclude dependencies from build" ([1c15a08](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/1c15a080ed33b6c62c52a24bf76077a2163ac694)) 7 | 8 | ## [1.10.10](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.10.9...v1.10.10) (2025-02-27) 9 | 10 | 11 | ### Bug Fixes 12 | 13 | * exclude dependencies from build ([af4bbce](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/af4bbce75695bf448f4b98e8195f2273b2f23417)) 14 | 15 | ## [1.10.9](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.10.8...v1.10.9) (2025-02-27) 16 | 17 | 18 | ### Bug Fixes 19 | 20 | * package only dist/ ([99b8501](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/99b8501a1c884df5d7869a665576be532ff298d1)) 21 | 22 | ## [1.10.8](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.10.7...v1.10.8) (2025-02-24) 23 | 24 | 25 | ### Bug Fixes 26 | 27 | * monkey patch should check options.detail ([4b78520](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/4b7852071468c7e40bb36698c7e61ea29da944e2)) 28 | 29 | ## [1.10.7](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.10.6...v1.10.7) (2025-01-07) 30 | 31 | ## [1.10.6](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.10.5...v1.10.6) (2024-07-29) 32 | 33 | 34 | ### Bug Fixes 35 | 36 | * force release ([4ed9b22](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/4ed9b229490cd422d30a6b20da9f04fb26555da2)) 37 | 38 | ## [1.10.5](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.10.4...v1.10.5) (2024-07-29) 39 | 40 | 41 | ### Bug Fixes 42 | 43 | * commit package-lock.json ([a4043f5](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/a4043f5fb6f4f5a15a111a19e52ef42503299df0)) 44 | 45 | ## [1.10.4](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.10.3...v1.10.4) (2024-01-06) 46 | 47 | ## [1.10.3](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.10.2...v1.10.3) (2024-01-06) 48 | 49 | 50 | ### Bug Fixes 51 | 52 | * unknown rule ([60fc3b8](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/60fc3b8d9ff43f799240135293e199f5f4f4d7c5)) 53 | 54 | ## [1.10.2](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.10.1...v1.10.2) (2024-01-05) 55 | 56 | 57 | ### Bug Fixes 58 | 59 | * error [ERR_MODULE_NOT_FOUND]: Cannot find module 'shortcss/lib/list' ([139a824](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/139a824c04cd53d805b0c1b94caa0a03f4baa0eb)) 60 | 61 | ## [1.10.1](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.10.0...v1.10.1) (2024-01-05) 62 | 63 | 64 | ### Bug Fixes 65 | 66 | * modern exports path ([8aa3570](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/8aa35705bb224c1717eed4b6ddb0a4da68e92e7e)) 67 | 68 | # [1.10.0](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.9.2...v1.10.0) (2024-01-05) 69 | 70 | 71 | ### Features 72 | 73 | * support stylelint v16 ([cf40d65](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/cf40d658970861282396f17a11efbdbfe768f43d)) 74 | 75 | ## [1.9.2](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.9.1...v1.9.2) (2023-02-16) 76 | 77 | 78 | ### Bug Fixes 79 | 80 | * eslint errors ([5639937](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/5639937dec9800f896c516a6aa97254c83889766)) 81 | * improve auto fix tests ([b525d61](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/b525d6112798d54f05d396bad30b2d881629fce0)) 82 | * migrate types ([e1c491f](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/e1c491fa956e95b8f78111f6f7dd4f86dbe8d4cf)) 83 | * uninstall deprecated stylint types ([8f01fee](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/8f01fee1e291406bb7edd9c8e0478a064056e25c)) 84 | * workaround missing options validation with jest styleint preset ([c25950b](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/c25950bf345709ad77d19f53a2fcad1ca26906b8)) 85 | 86 | ## [1.9.1](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.9.0...v1.9.1) (2022-10-13) 87 | 88 | 89 | ### Bug Fixes 90 | 91 | * [#276](https://github.com/AndyOGo/stylelint-declaration-strict-value/issues/276) remove console.error ([9f9a59d](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/9f9a59d4527f319b3b6e9b4b6749f7d275ab72c4)) 92 | 93 | # [1.9.0](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.8.0...v1.9.0) (2022-07-16) 94 | 95 | 96 | ### Features 97 | 98 | * handle thrown errors of autofix function ([868ae5c](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/868ae5c0912c2dc9d4b7323c6cc1b11f1dc08a7c)) 99 | 100 | # [1.8.0](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.7.12...v1.8.0) (2021-11-06) 101 | 102 | 103 | ### Features 104 | 105 | * support stylelint v14 ([3790437](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/37904375f9d508f3f6c15eac39caafd8b9d991c5)) 106 | 107 | ## [1.7.12](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.7.11...v1.7.12) (2021-04-16) 108 | 109 | ## [1.7.11](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.7.10...v1.7.11) (2021-04-16) 110 | 111 | 112 | ### Bug Fixes 113 | 114 | * expanded shorthand check ([91cdf8c](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/91cdf8c7345b0b648bf13f5aea38729a72a87575)) 115 | * keyword may be duplicated ([8ba4b47](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/8ba4b4799aa6224d3fe96e6ceb5de6715fa4a4d4)) 116 | * shorthand value check should ignore variables and functions ([0556434](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/0556434efae4859d8bd26c61c30ebf3b1afba8d9)) 117 | 118 | ## [1.7.10](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.7.9...v1.7.10) (2021-04-02) 119 | 120 | 121 | ### Bug Fixes 122 | 123 | * import declaration files ([e862a5e](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/e862a5efab771727ed40ac0c3918d58a395e1379)) 124 | * only execute autofix func if it could be found ([f5b20e3](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/f5b20e3455410d25ca0446b47440c7b661d9fb0d)) 125 | 126 | ## [1.7.9](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.7.8...v1.7.9) (2021-02-25) 127 | 128 | ## [1.7.8](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.7.7...v1.7.8) (2021-02-25) 129 | 130 | 131 | ### Bug Fixes 132 | 133 | * delete stylints custom message override ([dc6efc1](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/dc6efc1218c7966c810698c00061e26cb0b92358)) 134 | * eslint ([f073de4](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/f073de4e0236a6cf10ea858c21291e8586924f09)) 135 | 136 | ## [1.7.7](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.7.6...v1.7.7) (2021-01-03) 137 | 138 | 139 | ### Bug Fixes 140 | 141 | * generate assets for release ([d063f75](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/d063f7546a1f514376acdfd88af29d3c4e7e700f)) 142 | 143 | ## [1.7.6](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.7.5...v1.7.6) (2021-01-03) 144 | 145 | 146 | ### Bug Fixes 147 | 148 | * add typeRoots to build config too ([ee94cd2](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/ee94cd28cd42aa06cf3f1887c1755204796b04fc)) 149 | * add types dir to typeRoots ([caaae6a](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/caaae6a72b52d9ea70fa29aea7623ebdef4edcae)) 150 | * entry point missing ([cc3cdc3](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/cc3cdc3576de17a1c242c43cbee2f7efe051e48e)) 151 | * remove mode and inputFiles options ([85dd4b8](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/85dd4b87338fd3fdb0bb80090fa51c77b29d87ed)) 152 | * typedoc config ([b3c0ae5](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/b3c0ae58a3855bf017b6bc0fac4c79a703feac17)) 153 | * typos ([4d809bd](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/4d809bd3109dfb8744cf10b3ca4e942de92a4db1)) 154 | 155 | ## [1.7.5](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.7.4...v1.7.5) (2020-11-29) 156 | 157 | 158 | ### Bug Fixes 159 | 160 | * remove hungarian notations ([64c5885](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/64c58858602137f16d8983a2e1f646d432216826)) 161 | 162 | ## [1.7.4](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.7.3...v1.7.4) (2020-11-29) 163 | 164 | 165 | ### Bug Fixes 166 | 167 | * type of primary options ([8010392](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/8010392b912c95d6943ef1407cd7000d4f59523e)) 168 | 169 | ## [1.7.3](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.7.2...v1.7.3) (2020-11-29) 170 | 171 | ## [1.7.2](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.7.1...v1.7.2) (2020-11-28) 172 | 173 | ## [1.7.1](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.7.0...v1.7.1) (2020-11-28) 174 | 175 | 176 | ### Bug Fixes 177 | 178 | * broken terser minification ([5cb14c4](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/5cb14c418db74c453acffedd79651254bb7119cc)) 179 | * charAt undefined error documentationjs ([9a695bb](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/9a695bb6ec05e20c817e0852a9f1cc1fd9c5fe95)) 180 | * lint error ([c362de1](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/c362de14270535b9756badb1ac0f4991507340cb)) 181 | * types of StyleLint/PostCSS ([2ae40b9](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/2ae40b9a9d880a4c2f5c329f726fcf25c3cde762)) 182 | 183 | # [1.7.0](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.6.0...v1.7.0) (2020-11-19) 184 | 185 | 186 | ### Bug Fixes 187 | 188 | * skip expanded shorthan if invalid and not variable or function ([0d69d33](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/0d69d3376b8d153e5818153b0a454715586ac012)) 189 | 190 | 191 | ### Features 192 | 193 | * split multi-value properties ([f087e35](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/f087e35a59c1051c81d96e1efc3f6b14afc70336)) 194 | 195 | ## [1.6.1](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.6.0...v1.6.1) (2020-10-29) 196 | 197 | 198 | ### Bug Fixes 199 | 200 | * skip expanded shorthan if invalid and not variable or function ([0d69d33](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/0d69d3376b8d153e5818153b0a454715586ac012)) 201 | 202 | # [1.6.0](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.5.0...v1.6.0) (2020-09-06) 203 | 204 | 205 | ### Features 206 | 207 | * support basic var and func hash ([2a097bc](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/2a097bcdd0db4638ac2144580ad7e084ee5d8a93)) 208 | * validate var und func options for optional hash ([873ab5d](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/873ab5d4df622b12e5ed4100a2b4219168c36d6a)) 209 | 210 | # [1.5.0](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.4.7...v1.5.0) (2020-05-29) 211 | 212 | 213 | ### Bug Fixes 214 | 215 | * eslint missing return doclet ([437f671](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/437f671eae39f88bacb794b43f610ab9b569167a)) 216 | 217 | 218 | ### Features 219 | 220 | * support css-loader [@value](https://github.com/value) ([a466b38](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/a466b38cdbc7762cb4d2ca93e0a1082f190a55f2)) 221 | * support css-loader [@value](https://github.com/value) ([8931d2f](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/8931d2f2d14286819e4e39e55e826d2cdecc962f)) 222 | 223 | ## [1.4.7](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.4.6...v1.4.7) (2020-05-25) 224 | 225 | ## [1.4.6](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.4.5...v1.4.6) (2020-05-19) 226 | 227 | ## [1.4.5](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.4.4...v1.4.5) (2020-05-19) 228 | 229 | 230 | ### Bug Fixes 231 | 232 | * always mark original node prop, also for shorthands ([9e4fd98](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/9e4fd9865cd9af2ccb073ab4f8756cf4daa43d1b)) 233 | * check shorthand if configured ([05255fb](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/05255fbe8b6c4810c524a2614ef450ae87be38b1)) 234 | * eslint error ([5f5d50d](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/5f5d50d449ba924c0a13c685b30f8c95e7dd798f)) 235 | * shorthand should only reject once ([ce46c63](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/ce46c6337e45de106d4cb9c6ec47fc95cda47179)) 236 | 237 | ## [1.4.4](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.4.3...v1.4.4) (2020-05-14) 238 | 239 | ## [1.4.3](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.4.2...v1.4.3) (2020-04-30) 240 | 241 | 242 | ### Bug Fixes 243 | 244 | * disable expandShorthand by default ([5c1fe00](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/5c1fe00b821c986275cbc34e24fcf569c6016a4c)) 245 | 246 | ## [1.4.2](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.4.1...v1.4.2) (2020-04-28) 247 | 248 | ## [1.4.1](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.4.0...v1.4.1) (2020-04-28) 249 | 250 | # [1.4.0](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.3.6...v1.4.0) (2020-04-27) 251 | 252 | 253 | ### Bug Fixes 254 | 255 | * shorthand config was not validated ([eb34f80](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/eb34f80d3952045a51ef20252d343268177a6c50)) 256 | * typo ([34444f0](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/34444f0c57490aef41133c0d47092984f36a29a5)) 257 | 258 | 259 | ### Features 260 | 261 | * added shorthand support ([3cfd8af](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/3cfd8afad351d11ff77a9f7242cdb5cd44beef02)) 262 | 263 | ## [1.3.6](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.3.5...v1.3.6) (2020-04-26) 264 | 265 | ## [1.3.5](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.3.4...v1.3.5) (2020-04-25) 266 | 267 | ## [1.3.4](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.3.3...v1.3.4) (2020-04-25) 268 | 269 | ## [1.3.3](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.3.2...v1.3.3) (2020-04-25) 270 | 271 | 272 | ### Bug Fixes 273 | 274 | * dev stuff published on npm ([1725fac](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/1725fac356a41b178baf1d9548ccae33dac7ca46)) 275 | 276 | ## [1.3.2](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.3.1...v1.3.2) (2020-04-25) 277 | 278 | 279 | ### Bug Fixes 280 | 281 | * dev stuff published on npm ([8c1954c](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/8c1954cb9c700af8b0803285956b0a921ec79edf)) 282 | 283 | ## [1.3.1](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.3.0...v1.3.1) (2020-04-25) 284 | 285 | # [1.3.0](https://github.com/AndyOGo/stylelint-declaration-strict-value/compare/v1.2.3...v1.3.0) (2020-04-25) 286 | 287 | 288 | ### Bug Fixes 289 | 290 | * disableFix is a boolean value ([3499c62](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/3499c62bd6f11ba07f8ca805d4ac73a8f78e7947)) 291 | * keyword regex did not have start and end markers for each item ([390c3e8](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/390c3e849f326dbf536ba6ab53f7f0ca9900310b)) 292 | 293 | 294 | ### Features 295 | 296 | * add regex flags and finish ignoreValues ([3608e89](https://github.com/AndyOGo/stylelint-declaration-strict-value/commit/3608e894ad18c462150c2955080babc830fd2109)) 297 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Andreas Deuschlinger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | ['@babel/preset-env', { targets: { node: 'current' } }], 4 | '@babel/preset-typescript', 5 | ], 6 | }; 7 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'], 3 | }; 4 | -------------------------------------------------------------------------------- /dist/defaults.d.ts: -------------------------------------------------------------------------------- 1 | import type { Node, Root } from 'postcss'; 2 | /** 3 | * Rule Name. 4 | */ 5 | export declare const ruleName = "scale-unlimited/declaration-strict-value"; 6 | /** 7 | * A hash of CSS properties to ignore variables or functions. 8 | */ 9 | export interface IgnoreVariableOrFunctionHash { 10 | [key: string]: boolean; 11 | } 12 | /** 13 | * Possible config for `ignoreVariables` and `ignoreFunctions` option. 14 | */ 15 | export declare type IgnoreVariableOrFunctionConfig = boolean | IgnoreVariableOrFunctionHash; 16 | /** 17 | * A Regular Expression string to match a CSS property or value. 18 | */ 19 | export declare type RegExpString = string; 20 | /** 21 | * A CSS value to be ignored. 22 | */ 23 | export declare type IgnoreValue = number | string | RegExpString; 24 | /** 25 | * A list of CSS values to be ignored. 26 | */ 27 | export declare type IgnoreValueList = Array; 28 | /** 29 | * A hash of CSS properties with ignored values. 30 | * - `''` key applies to all configured CSS properties. 31 | * - key can also be a Regular Expression string. 32 | */ 33 | export interface IgnoreValueHash { 34 | '': IgnoreValue | IgnoreValueList; 35 | [CSSPropertyName: string]: IgnoreValue | IgnoreValueList; 36 | } 37 | /** 38 | * @internal 39 | */ 40 | export declare const isIIgnoreValueHash: (key: unknown, value: unknown) => key is IgnoreValueHash; 41 | /** 42 | * Possible config for `ignoreValues` and ~~`ignoreKeywords`~~ option. 43 | */ 44 | export declare type IgnoreValueConfig = null | IgnoreValue | IgnoreValueList | IgnoreValueHash; 45 | /** 46 | * Result of CSS value validation. 47 | */ 48 | export interface DeclarationStrictValueResult { 49 | /** 50 | * Whether or not variable is valid. 51 | */ 52 | validVar: boolean; 53 | /** 54 | * Whether or not function is valid. 55 | */ 56 | validFunc: boolean; 57 | /** 58 | * Whether or not keyword is valid. 59 | */ 60 | validKeyword: boolean; 61 | /** 62 | * Whether or not value is valid. 63 | */ 64 | validValue: boolean; 65 | /** 66 | * Longhand CSS Property, if expanded. 67 | */ 68 | longhandProp?: string; 69 | /** 70 | * Longhand CSS value, if expanded. 71 | */ 72 | longhandValue?: string; 73 | } 74 | /** 75 | * A autofix function. 76 | */ 77 | export declare type AutoFixFunc = (node: Node, result: DeclarationStrictValueResult, root: Root, config: SecondaryOptions) => string; 78 | /** 79 | * Path to autofix function module. 80 | */ 81 | export declare type AutoFixModule = string; 82 | /** 83 | * Possible config for `autoFixFunc` option. 84 | */ 85 | export declare type AutoFixFuncConfig = null | undefined | AutoFixModule | AutoFixFunc; 86 | /** 87 | * Plugin secondary options. 88 | */ 89 | export interface SecondaryOptions { 90 | /** 91 | * Whether or not to ignore variables. 92 | * 93 | * @defaultValue true 94 | */ 95 | ignoreVariables?: IgnoreVariableOrFunctionConfig; 96 | /** 97 | * Whether or not to ignore function. 98 | * 99 | * @defaultValue true 100 | */ 101 | ignoreFunctions?: IgnoreVariableOrFunctionConfig; 102 | /** 103 | * An ignored keywords config. 104 | * 105 | * @defaultValue null 106 | * @deprecated use `ignoreValues` option. 107 | */ 108 | ignoreKeywords?: IgnoreValueConfig; 109 | /** 110 | * An ignored values config. 111 | * 112 | * @defaultValue null 113 | */ 114 | ignoreValues?: IgnoreValueConfig; 115 | /** 116 | * Whether or not to expand shorthand CSS properties. 117 | * 118 | * @defaultValue false 119 | */ 120 | expandShorthand?: boolean; 121 | /** 122 | * Whether or not to expand longhand CSS properties recursivly - this is only useful for the `border` property. 123 | * 124 | * @defaultValue false 125 | */ 126 | recurseLonghand?: boolean; 127 | /** 128 | * Adjust severity of the rule, `'warning'` or `'error'` (default). 129 | * 130 | * @defaultValue 'error' 131 | */ 132 | severity?: string; 133 | /** 134 | * A custom message when a rule is violated, interpolated with `${types}`, `${value}` and `${property}`. 135 | * 136 | * @defaultValue undefined 137 | */ 138 | message?: string; 139 | /** 140 | * Don't auto-fix if `--fix` option is applied. 141 | * 142 | * @defaultValue false 143 | */ 144 | disableFix?: boolean; 145 | /** 146 | * By default no auto-fix feature. 147 | * 148 | * @defaultValue null 149 | */ 150 | autoFixFunc?: AutoFixFuncConfig; 151 | } 152 | declare const defaults: SecondaryOptions; 153 | export default defaults; 154 | -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | import stylelint, { Rule, RuleMeta } from 'stylelint'; 2 | import { customExpected, expected, failedToFix } from './lib/validation'; 3 | import { ruleName, SecondaryOptions, RegExpString } from './defaults'; 4 | declare const meta: RuleMeta; 5 | declare const messages: { 6 | expected: typeof expected; 7 | customExpected: typeof customExpected; 8 | failedToFix: typeof failedToFix; 9 | }; 10 | /** 11 | * A string or regular expression matching a CSS property name. 12 | */ 13 | declare type CSSPropertyName = string | RegExpString; 14 | /** 15 | * Primary options, a CSS property or list of CSS properties to lint. 16 | * - Regular Expression strings are supported 17 | */ 18 | declare type PrimaryOptions = CSSPropertyName | CSSPropertyName[]; 19 | /** 20 | * Stylelint declaration strict value rule function. 21 | * 22 | * @see https://stylelint.io/developer-guide/plugins 23 | * @param properties - Primary options, a CSS property or list of CSS properties to lint. 24 | * @param options- Secondary options, configure edge cases. 25 | * @param context - Only used for autofixing. 26 | * 27 | * @returns Returns a PostCSS Plugin. 28 | */ 29 | declare type StylelintPlugin

= Rule; 30 | declare const ruleFunction: StylelintPlugin; 31 | declare const declarationStrictValuePlugin: stylelint.Plugin; 32 | export default declarationStrictValuePlugin; 33 | export { ruleName, messages, meta, ruleFunction as rule }; 34 | -------------------------------------------------------------------------------- /dist/index.modern.js: -------------------------------------------------------------------------------- 1 | import e from"stylelint";import n from"shortcss";import t from"shortcss/lib/list";import r from"css-values";import o from"path";function s(){return(s=Object.assign?Object.assign.bind():function(e){for(var n=1;n"object"==typeof e&&Object.hasOwnProperty.call(e,n),l={ignoreVariables:!0,ignoreFunctions:!0,ignoreKeywords:null,ignoreValues:null,expandShorthand:!1,recurseLonghand:!1,severity:"error",message:void 0,disableFix:!1,autoFixFunc:null};function u(e){const n=typeof e;return"string"===n||"number"===n}function c(e){return u(e)||Array.isArray(e)&&e.every(e=>u(e))}function f(e){return!("object"!=typeof e||!e)&&Object.keys(e).every(n=>c(e[n]))}function p(e){return!("object"!=typeof e||!e)&&Object.keys(e).every(n=>"boolean"==typeof e[n])}function g(e){if("object"!=typeof e)return!1;const n=Object.keys(l);return!(!Object.keys(e).every(e=>n.indexOf(e)>-1)||"ignoreVariables"in e&&"boolean"!=typeof e.ignoreVariables&&!p(e.ignoreVariables)&&null!==e.ignoreVariables||"ignoreFunctions"in e&&"boolean"!=typeof e.ignoreFunctions&&!p(e.ignoreFunctions)&&null!==e.ignoreFunctions||"severity"in e&&"string"!=typeof e.severity&&null!==e.severity||"ignoreKeywords"in e&&!c(e.ignoreKeywords)&&!f(e.ignoreKeywords)||"ignoreValues"in e&&!c(e.ignoreValues)&&!f(e.ignoreValues)||"expandShorthand"in e&&"boolean"!=typeof e.expandShorthand&&null!==e.expandShorthand||"recurseLonghand"in e&&"boolean"!=typeof e.recurseLonghand&&null!==e.recurseLonghand||"message"in e&&"string"!=typeof e.message&&null!==e.message||"disableFix"in e&&"boolean"!=typeof e.disableFix&&null!==e.disableFix||"autoFixFunc"in e&&"function"!=typeof e.autoFixFunc&&"string"!=typeof e.autoFixFunc&&null!==e.autoFixFunc)}function y(e){let n;if(Array.isArray(e)){const t=e.pop();n=e.length?`${e.join(", ")} or ${t}`:t}else n=e;return n}function d(e,n){return"boolean"==typeof e?e:"object"==typeof e&&e&&{}.hasOwnProperty.call(e,n)?e[n]:!!e}function h(e,n){if(!e)return null;let t=e;return a(t,n)?t=t[n]:a(t,"")&&(t=t[""]),Array.isArray(t)?t:[t]}function b(e,n){if(!e)return null;let t=e;return a(t,n)?t=t[n]:a(t,"")&&(t=t[""]),Array.isArray(t)?t:[t]}const{utils:x}=e,m=x.ruleMessages(i,{expected:function(e,n,t){return`Expected ${e} for "${n}" of "${t}"`},customExpected:function(e,n,t,r){return r.replace("${types}",e).replace("${value}",n).replace("${property}",t)},failedToFix:function(e,n,t){return e&&("string"==typeof e||e instanceof Error)?"string"==typeof e?e:e.message:`Property "${t}" with value "${n}" can't be autofixed`}}),v=/^(?:@|\$|--).+$/,F=/^-?(?:@.+|(?:(?:[a-zA-Z_-]|[^\x20-\x7F])+(?:[a-zA-Z0-9_-]|[^\x20-\x7F])*\.)?\$.+|var\(\s*--[\s\S]+\))$/,w=/^(?!var\(\s*--)[\s\S]+\([\s\S]*\)$/,$=/^\/(.*)\/([a-zA-Z]*)$/,j=/color/,O=e=>$.test(e),V=e=>{const[n,t]=(e=>e.match($).slice(1))(e);return new RegExp(n,t)},A=e=>O(""+e)?V(""+e):new RegExp(`^${e}$`),E=(e,a,u={})=>(f,p)=>{if(p&&p.stylelint&&p.stylelint.customMessages&&p.stylelint.customMessages[i]&&delete p.stylelint.customMessages[i],!x.validateOptions(p,i,{actual:e,possible:c},{actual:a,possible:g,optional:!0}))return;Array.isArray(e)||(e=[e]);const $=s({},l,a),{ignoreVariables:E,ignoreFunctions:k,ignoreKeywords:S,ignoreValues:K,message:R,disableFix:P,autoFixFunc:L,expandShorthand:M,recurseLonghand:N}=$,q=function(e,n,t){if("function"==typeof e)return e;if("string"==typeof e){let n;try{n=require.resolve(e)}catch(t){n=require.resolve(o.join(process.cwd(),e))}return require(n)}return!n&&t&&console.warn(`No \`autoFix\` function provided, consider using \`disableFix\` for "${i}"`),null}(L,P,u.fix),z=S?{}:null,Z=K?{}:null;let T;if(E){const e=[];f.walkAtRules("value",n=>{const{params:t}=n,r=t.split(":")[0].trim();e.push(r)}),T=new RegExp(`^-?(:?${e.join("|")})$`)}e.forEach(e=>{let o=e;function s(n,t,o,s=!1){const{value:a,prop:l}=n,c=o||a;let g=!1,v=!1,O=!1,V=!1;if(E&&d(E,e)&&(g=F.test(c)||T.test(c)),k&&!g&&d(k,e)&&(v=w.test(c)),s&&(!E||E&&!g)&&(!k||k&&!v)&&!0!==((e,n)=>j.test(e)&&"transparent"===n||F.test(n)||w.test(n)||r(e,n))(t,o))return!1;if(S&&(!g||!v)){let n=z[e];if(!n){const t=h(S,e);t&&(n=new RegExp(`^${t.join("$|^")}$`),z[e]=n)}n&&(O=n.test(c))}if(K&&(!g||!v||!O)){let n=Z[e];if(!n){const t=b(K,e);t&&(n=t.map(A),Z[e]=n)}n&&(V=n.filter(e=>e.test(c)).length>0)}if(!(g||v||O||V)){const r=function(e,n){const{ignoreVariables:t,ignoreFunctions:r,ignoreKeywords:o,ignoreValues:s}=e,i=[];return t&&i.push("variable"),r&&i.push("function"),o&&h(o,n)&&i.push("keyword"),-1===i.indexOf("keyword")&&s&&b(s,n)&&i.push("keyword"),i}($,e);if(u.fix&&!P&&q)try{const e=q(n,{validVar:g,validFunc:v,validKeyword:O,validValue:V,longhandProp:t,longhandValue:o},f,$);e&&(n.value=e)}catch(e){const{raws:t}=n,r=n.source.start;x.report({ruleName:i,result:p,node:n,line:r.line,column:r.column+l.length+t.between.length,message:m.failedToFix(e,c,l)})}else{const{raws:e}=n,t=n.source.start;x.report({ruleName:i,result:p,node:n,line:t.line,column:t.column+l.length+e.between.length,message:R?m.customExpected(y(r),c,l,R):m.expected(y(r),c,l)})}return!0}return!1}O(o)&&(o=V(o)),f.walkDecls(function(e){const{value:r,prop:i}=e;if(v.test(i))return;const a=M&&n.isShorthand(i);if(i===o||!a&&o instanceof RegExp&&o.test(i)){const n=t.space(r);if(n.length>1){let t=!1;n.forEach(n=>{t||(t=s(e,i,n))})}else s(e)}else if(a){const t=n.expand(i,r,N);let a=!1;Object.keys(t).forEach(n=>{const r=t[n];!a&&(n===o||o instanceof RegExp&&o.test(n))&&(a=s(e,n,r,!0))})}})})};E.primaryOptionArray=!0,E.ruleName=i,E.messages=m;const k=e.createPlugin(i,E);export default k;export{m as messages,i as ruleName}; 2 | //# sourceMappingURL=index.modern.js.map 3 | -------------------------------------------------------------------------------- /dist/index.modern.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.modern.js","sources":["../src/defaults.ts","../src/lib/validation.ts","../src/index.ts"],"sourcesContent":["import type { Node, Root } from 'stylelint/node_modules/postcss';\n\n/**\n * Rule Name.\n */\nexport const ruleName = 'scale-unlimited/declaration-strict-value';\n\n/**\n * A hash of CSS properties to ignore variables or functions.\n */\nexport interface IgnoreVariableOrFunctionHash {\n [key: string]: boolean;\n}\n/**\n * Possible config for `ignoreVariables` and `ignoreFunctions` option.\n */\nexport type IgnoreVariableOrFunctionConfig =\n | boolean\n | IgnoreVariableOrFunctionHash;\n/**\n * A Regular Expression string to match a CSS property or value.\n */\nexport type RegExpString = string;\n/**\n * A CSS value to be ignored.\n */\nexport type IgnoreValue = number | string | RegExpString;\n/**\n * A list of CSS values to be ignored.\n */\nexport type IgnoreValueList = Array;\n/**\n * A hash of CSS properties with ignored values.\n * - `''` key applies to all configured CSS properties.\n * - key can also be a Regular Expression string.\n */\nexport interface IgnoreValueHash {\n '': IgnoreValue | IgnoreValueList;\n [CSSPropertyName: string]: IgnoreValue | IgnoreValueList;\n // [CSSPropertyName: TRegExpString]: TIgnoreValue | TIgnoreValueList;\n}\n/**\n * @internal\n */\nexport const isIIgnoreValueHash = (\n key: unknown,\n value: unknown\n): key is IgnoreValueHash =>\n typeof key === 'object' && Object.hasOwnProperty.call(key, value);\n/**\n * Possible config for `ignoreValues` and ~~`ignoreKeywords`~~ option.\n */\nexport type IgnoreValueConfig =\n | null\n | IgnoreValue\n | IgnoreValueList\n | IgnoreValueHash;\n/**\n * Result of CSS value validation.\n */\nexport interface DeclarationStrictValueResult {\n /**\n * Whether or not variable is valid.\n */\n validVar: boolean;\n\n /**\n * Whether or not function is valid.\n */\n validFunc: boolean;\n\n /**\n * Whether or not keyword is valid.\n */\n validKeyword: boolean;\n\n /**\n * Whether or not value is valid.\n */\n validValue: boolean;\n\n /**\n * Longhand CSS Property, if expanded.\n */\n longhandProp?: string;\n\n /**\n * Longhand CSS value, if expanded.\n */\n longhandValue?: string;\n}\n/**\n * A autofix function.\n */\nexport type AutoFixFunc = (\n node: Node,\n result: DeclarationStrictValueResult,\n root: Root,\n config: SecondaryOptions\n) => string;\n/**\n * Path to autofix function module.\n */\nexport type AutoFixModule = string;\n/**\n * Possible config for `autoFixFunc` option.\n */\nexport type AutoFixFuncConfig = null | undefined | AutoFixModule | AutoFixFunc;\n\n/**\n * Plugin secondary options.\n */\nexport interface SecondaryOptions {\n /**\n * Whether or not to ignore variables.\n *\n * @defaultValue true\n */\n ignoreVariables?: IgnoreVariableOrFunctionConfig;\n\n /**\n * Whether or not to ignore function.\n *\n * @defaultValue true\n */\n ignoreFunctions?: IgnoreVariableOrFunctionConfig;\n\n /**\n * An ignored keywords config.\n *\n * @defaultValue null\n * @deprecated use `ignoreValues` option.\n */\n ignoreKeywords?: IgnoreValueConfig;\n\n /**\n * An ignored values config.\n *\n * @defaultValue null\n */\n ignoreValues?: IgnoreValueConfig;\n\n /**\n * Whether or not to expand shorthand CSS properties.\n *\n * @defaultValue false\n */\n expandShorthand?: boolean;\n\n /**\n * Whether or not to expand longhand CSS properties recursivly - this is only useful for the `border` property.\n *\n * @defaultValue false\n */\n recurseLonghand?: boolean;\n\n /**\n * Adjust severity of the rule, `'warning'` or `'error'` (default).\n *\n * @defaultValue 'error'\n */\n severity?: string;\n\n /**\n * A custom message when a rule is violated, interpolated with `${types}`, `${value}` and `${property}`.\n *\n * @defaultValue undefined\n */\n message?: string;\n\n /**\n * Don't auto-fix if `--fix` option is applied.\n *\n * @defaultValue false\n */\n disableFix?: boolean;\n\n /**\n * By default no auto-fix feature.\n *\n * @defaultValue null\n */\n autoFixFunc?: AutoFixFuncConfig;\n}\n\nconst defaults: SecondaryOptions = {\n ignoreVariables: true,\n ignoreFunctions: true,\n ignoreKeywords: null,\n ignoreValues: null,\n expandShorthand: false,\n recurseLonghand: false,\n severity: 'error',\n message: undefined,\n disableFix: false,\n autoFixFunc: null,\n};\n\nexport default defaults;\n","import path from 'path';\n\nimport defaults, {\n ruleName,\n SecondaryOptions,\n IgnoreValue,\n IgnoreValueList,\n IgnoreValueHash,\n IgnoreVariableOrFunctionConfig,\n IgnoreVariableOrFunctionHash,\n IgnoreValueConfig,\n AutoFixFunc,\n AutoFixFuncConfig,\n isIIgnoreValueHash,\n} from '../defaults';\n\n/**\n * Check if type is either `number` or `string`.\n *\n * @internal\n * @param value - Any value.\n *\n * @returns Returns `true` if `value`'s type is either `number` or `string`, else `false`.\n */\nfunction isNumberOrString(value: unknown): value is IgnoreValue {\n const type = typeof value;\n\n return type === 'string' || type === 'number';\n}\n\n/**\n * Validate primary options of stylelint plugin config.\n *\n * @internal\n * @param actual - The actual config to validate.\n *\n * @returns Returns `true` if primary options are valid, else `false`.\n */\nexport function validProperties(\n actual: unknown\n): actual is IgnoreValue | IgnoreValueList {\n return (\n isNumberOrString(actual) ||\n (Array.isArray(actual) && actual.every((item) => isNumberOrString(item)))\n );\n}\n\n/**\n * Validate optional hash keyword config.\n *\n * @internal\n * @param actual - A keyword config.\n *\n * @returns Returns `true` if hash keyword config is valid, else `false`.\n */\nfunction validHash(actual: unknown): actual is IgnoreValueHash {\n if (typeof actual !== 'object' || !actual) return false;\n\n return Object.keys(actual).every((key) =>\n validProperties((actual as IgnoreValueHash)[key as keyof IgnoreValueHash])\n );\n}\n\n/**\n * Validate optional boolean hash variable/function config.\n *\n * @internal\n * @param actual - A variable/function config.\n *\n * @returns Returns `true` if hash variable/function config is valid, else `false`.\n */\nfunction validBooleanHash(\n actual: unknown\n): actual is IgnoreVariableOrFunctionHash {\n if (typeof actual !== 'object' || !actual) return false;\n\n return Object.keys(actual).every(\n (key) =>\n typeof (actual as IgnoreVariableOrFunctionHash)[\n key as keyof IgnoreVariableOrFunctionHash\n ] === 'boolean'\n );\n}\n\n/**\n * Validate optional secondary options of stylelint plugin config.\n *\n * @internal\n * @param actual - The actual config to validate.\n *\n * @returns Returns `true` if secondary options are valid, else `false`.\n */\nexport function validOptions(actual: SecondaryOptions): boolean {\n if (typeof actual !== 'object') return false;\n\n const allowedKeys = Object.keys(defaults);\n if (!Object.keys(actual).every((key) => allowedKeys.indexOf(key) > -1))\n return false;\n\n if (\n 'ignoreVariables' in actual &&\n typeof actual.ignoreVariables !== 'boolean' &&\n !validBooleanHash(actual.ignoreVariables) &&\n actual.ignoreVariables !== null\n )\n return false;\n\n if (\n 'ignoreFunctions' in actual &&\n typeof actual.ignoreFunctions !== 'boolean' &&\n !validBooleanHash(actual.ignoreFunctions) &&\n actual.ignoreFunctions !== null\n )\n return false;\n\n if (\n 'severity' in actual &&\n typeof actual.severity !== 'string' &&\n actual.severity !== null\n )\n return false;\n\n if (\n 'ignoreKeywords' in actual &&\n !validProperties(actual.ignoreKeywords) &&\n !validHash(actual.ignoreKeywords)\n )\n return false;\n\n if (\n 'ignoreValues' in actual &&\n !validProperties(actual.ignoreValues) &&\n !validHash(actual.ignoreValues)\n )\n return false;\n\n if (\n 'expandShorthand' in actual &&\n typeof actual.expandShorthand !== 'boolean' &&\n actual.expandShorthand !== null\n )\n return false;\n\n if (\n 'recurseLonghand' in actual &&\n typeof actual.recurseLonghand !== 'boolean' &&\n actual.recurseLonghand !== null\n )\n return false;\n\n if (\n 'message' in actual &&\n typeof actual.message !== 'string' &&\n actual.message !== null\n )\n return false;\n\n if (\n 'disableFix' in actual &&\n typeof actual.disableFix !== 'boolean' &&\n actual.disableFix !== null\n )\n return false;\n\n if (\n 'autoFixFunc' in actual &&\n typeof actual.autoFixFunc !== 'function' &&\n typeof actual.autoFixFunc !== 'string' &&\n actual.autoFixFunc !== null\n )\n return false;\n\n return true;\n}\n\n/**\n * Expected type of CSS value, available by configuration.\n * @internal\n */\ntype ExpectedType = 'variable' | 'function' | 'keyword';\n/**\n * Expected types of CSS value, as configured.\n * @internal\n */\ntype ExpectedTypes = Array;\n\n/**\n * Build expected message for stylelint report.\n *\n * @internal\n * @param types - Either `variable`, `function` and/or `keyword`.\n *\n * @returns Returns an expected types message for stylelint report.\n */\nexport function expectedTypes(types: ExpectedType | ExpectedTypes): string {\n let typesMessage: string;\n\n if (Array.isArray(types)) {\n const typesLast = types.pop();\n\n // eslint-disable-next-line no-param-reassign\n typesMessage = types.length\n ? `${types.join(', ')} or ${typesLast}`\n : (typesLast as string);\n } else {\n typesMessage = types;\n }\n\n return typesMessage;\n}\n\n/**\n * Build expected message for stylelint report.\n *\n * @internal\n * @param typesMessage - An expected types message for stylelint report.\n * @param value - The CSS declaration's value.\n * @param property - The CSS declaration's property.\n *\n * @returns Returns an expected message for stylelint report.\n */\nexport function expected(\n typesMessage: string,\n value: string,\n property: string\n): string {\n return `Expected ${typesMessage} for \"${value}\" of \"${property}\"`;\n}\n\n/**\n * Build custom expected message for stylelint report.\n *\n * @internal\n * @param typesMessage - An expected types message for stylelint report.\n * @param value - The CSS declaration's value.\n * @param property - The CSS declaration's property.\n * @param customMessage - A custom message to be delivered upon error interpolated with `${types}`, `${value}` and `${property}`.\n *\n * @returns Returns a custom expected message for stylelint report.\n */\nexport function customExpected(\n typesMessage: string,\n value: string,\n property: string,\n customMessage: string\n): string {\n /* eslint-disable no-template-curly-in-string */\n return customMessage\n .replace('${types}', typesMessage)\n .replace('${value}', value)\n .replace('${property}', property);\n /* eslint-enable no-template-curly-in-string */\n}\n\n/**\n * Build failed-to-fix message for stylelint report.\n *\n * @internal\n * @param error - An expression to `throw`.\n * @param value - The CSS declaration's value.\n * @param property - The CSS declaration's property.\n *\n * @returns Returns an failed-to-fix message for stylelint report.\n */\nexport function failedToFix(\n error: unknown,\n value: string,\n property: string\n): string {\n if (error && (typeof error === 'string' || error instanceof Error)) {\n return typeof error === 'string' ? error : error.message;\n }\n\n return `Property \"${property}\" with value \"${value}\" can't be autofixed`;\n}\n\n/**\n * Get configured types for stylelint report message.\n *\n * @internal\n * @param config - The secondary stylelint-plugin config.\n * @param property - The specific CSS declaration's property of the current iteration.\n *\n * @returns Returns a list of configured types.\n */\nexport function getTypes(\n config: SecondaryOptions,\n property: string\n): ExpectedTypes {\n const { ignoreVariables, ignoreFunctions, ignoreKeywords, ignoreValues } =\n config;\n const types: ExpectedTypes = [];\n\n if (ignoreVariables) {\n types.push('variable');\n }\n\n if (ignoreFunctions) {\n types.push('function');\n }\n\n if (ignoreKeywords && getIgnoredKeywords(ignoreKeywords, property)) {\n types.push('keyword');\n }\n\n if (\n types.indexOf('keyword') === -1 &&\n ignoreValues &&\n getIgnoredValues(ignoreValues, property)\n ) {\n types.push('keyword');\n }\n\n return types;\n}\n\n/**\n * Get the correct ignored variable or function for a specific CSS declaration's property\n * out of a complex `ignoreVariablesOrFunctions` config hash or boolean.\n *\n * @internal\n * @param ignoreVariablesOrFunctions - The variables or functions to ignore.\n * @param property - The specific CSS declaration's property of the current iteration.\n *\n * @returns Returns ignored variable or function for a specific CSS property.\n */\nexport function getIgnoredVariablesOrFunctions(\n ignoreVariablesOrFunctions: IgnoreVariableOrFunctionConfig,\n property: string\n): boolean {\n // @see: https://github.com/microsoft/TypeScript/issues/41627\n // const type = typeof ignoreVariablesOrFunctions\n\n if (typeof ignoreVariablesOrFunctions === 'boolean') {\n return ignoreVariablesOrFunctions;\n }\n\n if (\n typeof ignoreVariablesOrFunctions === 'object' &&\n ignoreVariablesOrFunctions &&\n {}.hasOwnProperty.call(ignoreVariablesOrFunctions, property)\n ) {\n return ignoreVariablesOrFunctions[property];\n }\n\n return !!ignoreVariablesOrFunctions;\n}\n\n/**\n * Get the correct ignored keywords for a specific CSS declaration's property\n * out of a complex `ignoreKeywords` config hash or array.\n *\n * @internal\n * @param ignoreKeywords - The keyword/-s to ignore.\n * @param property - The specific CSS declaration's property of the current iteration.\n *\n * @returns Returns ignored keywords for a specific CSS property, or `null`.\n */\nexport function getIgnoredKeywords(\n ignoreKeywords: IgnoreValueConfig,\n property: string\n): null | IgnoreValueList {\n if (!ignoreKeywords) return null;\n\n let keywords = ignoreKeywords;\n\n if (isIIgnoreValueHash(keywords, property)) {\n keywords = keywords[property];\n } else if (isIIgnoreValueHash(keywords, '')) {\n keywords = keywords[''];\n }\n\n return Array.isArray(keywords) ? keywords : [keywords];\n}\n\n/**\n * Get the correct ignored values for a specific CSS declaration's property\n * out of a complex `ignoreValues` config hash or array.\n *\n * @internal\n * @param ignoreValues - The values/-s to ignore.\n * @param property - The specific CSS declaration's property of the current iteration.\n * @returns Returns ignored values for a specific CSS property, or `null`.\n */\nexport function getIgnoredValues(\n ignoreValues: IgnoreValueConfig,\n property: string\n): null | IgnoreValueList {\n if (!ignoreValues) return null;\n\n let values = ignoreValues;\n\n if (isIIgnoreValueHash(values, property)) {\n values = values[property];\n } else if (isIIgnoreValueHash(values, '')) {\n values = values[''];\n }\n\n return Array.isArray(values) ? values : [values];\n}\n\n/**\n * Get the auto-fix function either by a function directly or from a source file.\n *\n * @internal\n * @param autoFixFunc - A JavaScript function or a module path to resolve it, also from `cwd`.\n *\n * @returns Returns the auto-fix function if found, else `null`.\n */\nexport function getAutoFixFunc(\n autoFixFunc: AutoFixFuncConfig,\n disableFix?: boolean,\n contextFix?: boolean\n): null | AutoFixFunc {\n // @see: https://github.com/microsoft/TypeScript/issues/41627\n // const type = typeof autoFixFunc\n\n if (typeof autoFixFunc === 'function') {\n return autoFixFunc;\n }\n\n if (typeof autoFixFunc === 'string') {\n let resolveAutoFixfunc;\n\n try {\n resolveAutoFixfunc = require.resolve(autoFixFunc);\n } catch (error) {\n resolveAutoFixfunc = require.resolve(\n path.join(process.cwd(), autoFixFunc)\n );\n }\n\n // eslint-disable-next-line import/no-dynamic-require, global-require\n return require(resolveAutoFixfunc);\n }\n\n if (!disableFix && contextFix) {\n // eslint-disable-next-line no-console\n console.warn(\n `No \\`autoFix\\` function provided, consider using \\`disableFix\\` for \"${ruleName}\"`\n );\n }\n\n return null;\n}\n","import type { Declaration, Root, AtRule } from 'stylelint/node_modules/postcss';\nimport stylelint, { PostcssResult, Rule } from 'stylelint';\nimport shortCSS from 'shortcss';\nimport list from 'shortcss/lib/list';\nimport cssValues from 'css-values';\n\nimport {\n validProperties,\n validOptions,\n expectedTypes,\n customExpected,\n expected,\n getTypes,\n getIgnoredVariablesOrFunctions,\n getIgnoredKeywords,\n getIgnoredValues,\n getAutoFixFunc,\n failedToFix,\n} from './lib/validation';\nimport defaults, {\n ruleName,\n SecondaryOptions,\n IgnoreValue,\n RegExpString,\n} from './defaults';\n\nconst { utils } = stylelint;\nconst messages = utils.ruleMessages(ruleName, {\n expected,\n customExpected,\n failedToFix,\n});\n/**\n * RegExp to skip non-CSS properties.\n *\n * @internal\n */\nconst reSkipProp = /^(?:@|\\$|--).+$/;\n/**\n * RegExp to parse CSS, SCSS and less variables.\n * - allowing CSS variables to be multi line\n * - Sass namespaces and CSS supported\n *\n * @internal\n * @see https://github.com/sass/sass/blob/master/accepted/module-system.md#member-references\n * @see https://drafts.csswg.org/css-syntax-3/#ident-token-diagram\n */\n// eslint-disable-next-line no-control-regex\nconst reVar =\n /^-?(?:@.+|(?:(?:[a-zA-Z_-]|[^\\x20-\\x7F])+(?:[a-zA-Z0-9_-]|[^\\x20-\\x7F])*\\.)?\\$.+|var\\(\\s*--[\\s\\S]+\\))$/;\n/**\n * RegExp to parse functions.\n * - irgnoring CSS variables `var(--*)`\n * - allow multi line arguments\n *\n * @internal\n */\nconst reFunc = /^(?!var\\(\\s*--)[\\s\\S]+\\([\\s\\S]*\\)$/;\n/**\n * RegExp to parse regular expressions.\n * - supporting patterns\n * - and optional flags\n *\n * @internal\n */\nconst reRegex = /^\\/(.*)\\/([a-zA-Z]*)$/;\n/**\n * @internal\n */\nconst reColorProp = /color/;\ntype RegExpArray = [string, string?];\n/**\n * Checks if string is a Regular Expression.\n *\n * @internal\n * @param value - Any string.\n */\nconst checkCssValue = (prop: string, value: string) =>\n (reColorProp.test(prop) && value === 'transparent') ||\n reVar.test(value) ||\n reFunc.test(value) ||\n cssValues(prop, value);\nconst isRegexString = (value: string): value is RegExpString =>\n reRegex.test(value);\n/**\n * Get pattern and flags of a Regular Expression string.\n *\n * @internal\n * @param value - Any string representing a Regular Expression.\n * @returns An Array of pattern and flags of a Regular Expression string.\n */\nconst getRegexString = (value: string): RegExpArray =>\n value.match(reRegex)!.slice(1) as RegExpArray;\n/**\n * Convert a Regular Expression string to an RegExp object.\n *\n * @internal\n * @param value - Any string representing a Regular Expression.\n * @returns A Regular Expression object.\n */\nconst stringToRegex = (value: RegExpString) => {\n const [pattern, flags] = getRegexString(value);\n return new RegExp(pattern, flags);\n};\n/**\n * Map ignored value config to a Regular expression.\n *\n * @internal\n * @param ignoreValue - A ignored value property.\n * @returns A Regular Expression to match ignored values.\n */\nconst mapIgnoreValue = (ignoreValue: IgnoreValue) =>\n isRegexString(`${ignoreValue}`)\n ? stringToRegex(`${ignoreValue}`)\n : new RegExp(`^${ignoreValue}$`);\n\n/**\n * A string or regular expression matching a CSS property name.\n */\ntype CSSPropertyName = string | RegExpString;\n\n/**\n * Primary options, a CSS property or list of CSS properties to lint.\n * - Regular Expression strings are supported\n */\ntype PrimaryOptions = CSSPropertyName | CSSPropertyName[];\n\ntype RuleContext = {\n fix?: boolean | undefined;\n newline?: string | undefined;\n};\n\n/**\n * Stylelint declaration strict value rule function.\n *\n * @see https://stylelint.io/developer-guide/plugins\n * @param properties - Primary options, a CSS property or list of CSS properties to lint.\n * @param options- Secondary options, configure edge cases.\n * @param context - Only used for autofixing.\n *\n * @returns Returns a PostCSS Plugin.\n */\ntype StylelintPlugin

= Rule;\n\nconst ruleFunction: StylelintPlugin =\n (\n properties: PrimaryOptions,\n options: SecondaryOptions,\n context: RuleContext = {}\n ) =>\n (root: Root, result: PostcssResult) => {\n // fix #142\n // @see https://github.com/stylelint/stylelint/pull/672/files#diff-78f1c80ffb2836008dd194b3b0ca28f9b46e4897b606f0b3d25a29e57a8d3e61R74\n // @see https://stylelint.io/user-guide/configure#message\n /* eslint-disable @typescript-eslint/no-explicit-any */\n if (\n result &&\n (result as any).stylelint &&\n (result as any).stylelint.customMessages &&\n (result as any).stylelint.customMessages[ruleName]\n ) {\n // eslint-disable-next-line no-param-reassign\n delete (result as any).stylelint.customMessages[ruleName];\n }\n /* eslint-enable @typescript-eslint/no-explicit-any */\n\n // validate stylelint plugin options\n const hasValidOptions = utils.validateOptions(\n result,\n ruleName,\n {\n actual: properties,\n possible: validProperties,\n },\n {\n actual: options,\n possible: validOptions,\n optional: true,\n }\n );\n\n if (!hasValidOptions) return;\n\n // normalize options\n if (!Array.isArray(properties)) {\n // eslint-disable-next-line no-param-reassign\n properties = [properties];\n }\n\n const config: SecondaryOptions = {\n ...defaults,\n ...options,\n };\n const {\n ignoreVariables,\n ignoreFunctions,\n ignoreKeywords,\n ignoreValues,\n message,\n disableFix,\n autoFixFunc,\n expandShorthand,\n recurseLonghand,\n } = config;\n const autoFixFuncNormalized = getAutoFixFunc(\n autoFixFunc,\n disableFix,\n context.fix\n );\n /**\n * A hash of regular expression to ignore for a CSS properties.\n * @internal\n */\n interface RegExpMap {\n // [key: CSSPropertyName]: RegExp;\n [key: string]: RegExp;\n }\n /**\n * A hash of regular expression to ignore for a CSS properties or `null`.\n * @internal\n */\n type RegExpKeywordMap = null | RegExpMap;\n /**\n * A hash of regular expression lists to ignore for a CSS property.\n * @internal\n */\n interface RegExpList {\n // [key: CSSPropertyName]: RegExp[];\n [key: string]: RegExp[];\n }\n /**\n * A hash of regular expression lists to ignore for a CSS property or `null`.\n * @internal\n */\n type RegExpValuesList = null | RegExpList;\n const reKeywords: RegExpKeywordMap = ignoreKeywords ? {} : null;\n const reValues: RegExpValuesList = ignoreValues ? {} : null;\n let cssLoaderValues: RegExp;\n\n if (ignoreVariables) {\n const cssLoaderValuesNames: string[] = [];\n root.walkAtRules('value', (rule: AtRule) => {\n const { params } = rule;\n const name = params.split(':')[0].trim();\n\n cssLoaderValuesNames.push(name);\n });\n\n cssLoaderValues = new RegExp(`^-?(:?${cssLoaderValuesNames.join('|')})$`);\n }\n\n // loop through all properties\n properties.forEach((property) => {\n let propFilter: string | RegExp = property;\n\n // parse RegExp\n if (isRegexString(propFilter)) {\n propFilter = stringToRegex(propFilter);\n }\n\n // walk through all declarations filtered by configured properties\n root.walkDecls(filterDecl);\n\n /**\n * Filter declarations for matching properties and expand shorthand properties.\n *\n * @internal\n * @param node - A Declaration-Node from PostCSS AST-Parser.\n */\n function filterDecl(node: Declaration) {\n const { value, prop } = node;\n\n // skip variable declarations\n if (reSkipProp.test(prop)) return;\n\n const isShortHand = expandShorthand && shortCSS.isShorthand(prop);\n\n if (\n prop === propFilter ||\n (!isShortHand &&\n propFilter instanceof RegExp &&\n propFilter.test(prop))\n ) {\n const values: string[] = list.space(value);\n\n // handle multi-value props, like scrollbar-color\n if (values.length > 1) {\n let failedFlag = false;\n\n values.forEach((valueItem) => {\n if (!failedFlag) {\n failedFlag = lintDeclStrictValue(node, prop, valueItem);\n }\n });\n } else {\n lintDeclStrictValue(node);\n }\n } else if (isShortHand) {\n const expandedProps = shortCSS.expand(prop, value, recurseLonghand);\n let failedFlag = false;\n\n Object.keys(expandedProps).forEach((longhandProp) => {\n const longhandValue = expandedProps[longhandProp];\n\n if (\n !failedFlag &&\n (longhandProp === propFilter ||\n (propFilter instanceof RegExp && propFilter.test(longhandProp)))\n ) {\n failedFlag = lintDeclStrictValue(\n node,\n longhandProp,\n longhandValue,\n true\n );\n }\n });\n }\n }\n\n /**\n * Lint usages of declarations values against, variables, functions\n * or custom keywords - as configured.\n *\n * @internal\n * @param node - A Declaration-Node from PostCSS AST-Parser.\n * @param longhandProp - A Declaration-Node from PostCSS AST-Parser.\n * @param longhandValue - A Declaration-Node from PostCSS AST-Parser.\n * @param isExpanded - Whether or not this declaration was expanded.\n * @returns Returns `true` if invalid declaration found, else `false`.\n */\n function lintDeclStrictValue(\n node: Declaration,\n longhandProp?: string,\n longhandValue?: string,\n isExpanded = false\n ) {\n const { value: nodeValue, prop: nodeProp } = node;\n const value = longhandValue || nodeValue;\n\n // falsify everything by default\n let validVar = false;\n let validFunc = false;\n let validKeyword = false;\n let validValue = false;\n\n // test variable\n if (ignoreVariables) {\n // @TODO: deviant regexes to primary options need to be evaluated\n const ignoreVariable = getIgnoredVariablesOrFunctions(\n ignoreVariables,\n property\n );\n\n if (ignoreVariable) {\n validVar = reVar.test(value) || cssLoaderValues.test(value);\n }\n }\n\n // test function\n if (ignoreFunctions && !validVar) {\n // @TODO: deviant regexes to primary options need to be evaluated\n const ignoreFunction = getIgnoredVariablesOrFunctions(\n ignoreFunctions,\n property\n );\n\n if (ignoreFunction) {\n validFunc = reFunc.test(value);\n }\n }\n\n // test expanded shorthands are valid\n if (\n isExpanded &&\n (!ignoreVariables || (ignoreVariables && !validVar)) &&\n (!ignoreFunctions || (ignoreFunctions && !validFunc)) &&\n checkCssValue(longhandProp!, longhandValue!) !== true\n ) {\n return false;\n }\n\n // test keywords\n if (ignoreKeywords && (!validVar || !validFunc)) {\n let reKeyword = reKeywords![property];\n\n if (!reKeyword) {\n const ignoreKeyword = getIgnoredKeywords(ignoreKeywords, property);\n\n if (ignoreKeyword) {\n reKeyword = new RegExp(`^${ignoreKeyword.join('$|^')}$`);\n reKeywords![property] = reKeyword;\n }\n }\n\n if (reKeyword) {\n validKeyword = reKeyword.test(value);\n }\n }\n\n if (ignoreValues && (!validVar || !validFunc || !validKeyword)) {\n let reValueList = reValues![property];\n\n if (!reValueList) {\n const ignoreValue = getIgnoredValues(ignoreValues, property);\n\n if (ignoreValue) {\n reValueList = ignoreValue.map(mapIgnoreValue);\n reValues![property] = reValueList;\n }\n }\n\n if (reValueList) {\n validValue =\n reValueList.filter((reValue) => reValue.test(value)).length > 0;\n }\n }\n\n // report only if all failed\n if (!validVar && !validFunc && !validKeyword && !validValue) {\n const types = getTypes(config, property);\n\n // support auto fixing\n if (context.fix && !disableFix && autoFixFuncNormalized) {\n try {\n const fixedValue = autoFixFuncNormalized(\n node,\n {\n validVar,\n validFunc,\n validKeyword,\n validValue,\n longhandProp,\n longhandValue,\n },\n root,\n config\n );\n\n // apply fixed value if returned\n if (fixedValue) {\n // eslint-disable-next-line no-param-reassign\n node.value = fixedValue;\n }\n } catch (error) {\n const { raws } = node;\n // eslint-disable-next-line prefer-destructuring\n const start = node.source!.start;\n\n utils.report({\n ruleName,\n result,\n node,\n line: start!.line,\n column: start!.column + nodeProp.length + raws.between!.length,\n message: messages.failedToFix(error, value, nodeProp),\n } as any);\n }\n } else {\n const { raws } = node;\n // eslint-disable-next-line prefer-destructuring\n const start = node.source!.start;\n\n utils.report({\n ruleName,\n result,\n node,\n line: start!.line,\n column: start!.column + nodeProp.length + raws.between!.length,\n message: message\n ? messages.customExpected(\n expectedTypes(types),\n value,\n nodeProp,\n message\n )\n : messages.expected(expectedTypes(types), value, nodeProp),\n } as any);\n }\n\n return true;\n }\n\n return false;\n }\n });\n };\n\nruleFunction.primaryOptionArray = true;\nruleFunction.ruleName = ruleName;\nruleFunction.messages = messages;\n\nconst declarationStrictValuePlugin = stylelint.createPlugin(\n ruleName,\n ruleFunction\n);\n\nexport default declarationStrictValuePlugin;\nexport { ruleName, messages };\n"],"names":["ruleName","key","value","Object","hasOwnProperty","call","ignoreVariables","ignoreFunctions","ignoreKeywords","ignoreValues","expandShorthand","recurseLonghand","severity","message","undefined","disableFix","autoFixFunc","type","actual","Array","isArray","every","item","isNumberOrString","keys","validProperties","defaults","allowedKeys","indexOf","validBooleanHash","validHash","types","pop","typesMessage","length","join","typesLast","ignoreVariablesOrFunctions","property","isIIgnoreValueHash","keywords","values","utils","stylelint","ruleMessages","expected","customExpected","customMessage","replace","failedToFix","error","reRegex","test","pattern","flags","match","slice","getRegexString","ignoreValue","isRegexString","stringToRegex","properties","options","context","root","result","customMessages","validateOptions","possible","validOptions","optional","config","contextFix","resolveAutoFixfunc","require","resolve","path","process","cwd","console","warn","getAutoFixFunc","fix","walkAtRules","rule","params","split","trim","cssLoaderValuesNames","push","name","cssLoaderValues","forEach","node","longhandProp","longhandValue","isExpanded","nodeValue","prop","nodeProp","getIgnoredVariablesOrFunctions","validVar","reVar","validFunc","reFunc","reColorProp","cssValues","checkCssValue","reKeywords","reKeyword","getIgnoredKeywords","ignoreKeyword","validKeyword","reValues","reValueList","getIgnoredValues","map","mapIgnoreValue","validValue","filter","reValue","getTypes","autoFixFuncNormalized","fixedValue","raws","source","start","report","line","column","between","messages","expectedTypes","propFilter","walkDecls","reSkipProp","shortCSS","isShorthand","isShortHand","list","space","valueItem","failedFlag","lintDeclStrictValue","expand","expandedProps","ruleFunction","primaryOptionArray","createPlugin"],"mappings":"mWAKaA,QAAW,6CAuCU,CAChCC,EACAC,IAEe,oBAAYC,OAAOC,eAAeC,KAAKJ,EAAKC,KAyI1B,CACjCI,iBAAiB,EACjBC,iBAAiB,EACjBC,eAAgB,KAChBC,aAAc,KACdC,iBAAiB,EACjBC,iBAAiB,EACjBC,SAAU,QACVC,aAASC,EACTC,YAAY,EACZC,YAAa,MC3Kf,WAA0Bd,GACxB,iBAEA,MAAgB,cAAqB,WAATe,EAW9B,WACEC,GAEA,SACmBA,IAChBC,MAAMC,QAAQF,IAAWA,EAAOG,MAAOC,GAASC,EAAiBD,IAYtE,WAAmBJ,GACjB,QAAsB,qBAAaA,WAErBM,KAAKN,GAAQG,MAAOpB,GAChCwB,EAAiBP,EAA2BjB,KAYhD,WACEiB,GAEA,QAAsB,qBAAaA,WAErBM,KAAKN,GAAQG,MACxBpB,GAGO,oBADJA,eAaqBiB,GAC3B,GAAsB,mBAAU,SAEhC,QAAoBf,OAAOqB,KAAKE,GAChC,SAAKvB,OAAOqB,KAAKN,GAAQG,MAAOpB,GAAQ0B,EAAYC,QAAQ3B,IAAQ,IAIlE,uBACkC,oBAApBK,kBACbuB,EAAiBX,EAAOZ,kBACE,OAA3BY,EAAOZ,iBAKP,uBACkC,oBAApBC,kBACbsB,EAAiBX,EAAOX,kBACE,OAA3BW,EAAOX,iBAKP,gBAC2B,mBAAbK,UACM,OAApBM,EAAON,UAKP,uBACCa,EAAgBP,EAAOV,kBACvBsB,EAAUZ,EAAOV,iBAKlB,qBACCiB,EAAgBP,EAAOT,gBACvBqB,EAAUZ,EAAOT,eAKlB,uBACkC,oBAApBC,iBACa,OAA3BQ,EAAOR,iBAKP,uBACkC,oBAApBC,iBACa,OAA3BO,EAAOP,iBAKP,eAC0B,mBAAZE,SACK,OAAnBK,EAAOL,SAKP,kBAC6B,oBAAfE,YACQ,OAAtBG,EAAOH,YAKP,mBAC8B,qBAAhBC,aACgB,mBAAhBA,aACS,OAAvBE,EAAOF,aA0BX,WAA8Be,GAC5B,MAEA,GAAIZ,MAAMC,QAAQW,GAAQ,CACxB,QAAkBA,EAAMC,MAGxBC,EAAeF,EAAMG,UACdH,EAAMI,KAAK,YAAYC,IACzBA,OAELH,EAAeF,EAGjB,SAsHF,WACEM,EACAC,GAKA,MAA0C,sBAKF,oBACtCD,GACA,GAAGjC,eAAeC,KAAKgC,EAA4BC,KAEjBA,KAG3BD,EAaX,WACE7B,EACA8B,GAEA,IAAK9B,EAAgB,YAErB,MAAeA,EAQf,OANI+B,EAAmBC,EAAUF,GAC/BE,EAAWA,EAASF,GACXC,EAAmBC,EAAU,MACtCA,EAAWA,EAAS,WAGTpB,QAAQoB,GAAYA,EAAW,CAACA,GAY/C,WACE/B,EACA6B,GAEA,IAAK7B,EAAc,YAEnB,MAAaA,EAQb,OANI8B,EAAmBE,EAAQH,GAC7BG,EAASA,EAAOH,GACPC,EAAmBE,EAAQ,MACpCA,EAASA,EAAO,WAGLrB,QAAQqB,GAAUA,EAAS,CAACA,GCpX3C,MAAMC,MAAEA,GAAUC,IACDD,EAAME,aAAa5C,EAAU,CAC5C6C,kBDkMAZ,EACA/B,EACAoC,GAEA,kBAAmBL,UAAqB/B,UAAcoC,MCrMtDQ,wBDoNAb,EACA/B,EACAoC,EACAS,GAGA,SACGC,QAAQ,WAAYf,GACpBe,QAAQ,WAAY9C,GACpB8C,QAAQ,cAAeV,IC5N1BW,YD0OF,SACEC,EACAhD,EACAoC,GAEA,OAAIY,IAA2B,oBAAYA,oBACjB,mBAAWA,EAAQA,EAAMrC,qBAG/ByB,kBAAyBpC,6BC5O5B,oBAYjB,2GAQa,uCAQC,0BAII,UAaGA,GACrBiD,EAAQC,KAAKlD,KAiBQA,IACrB,MAAOmD,EAASC,GAVMpD,CAAAA,GACtBA,EAAMqD,MAAMJ,GAAUK,MAAM,GASHC,CAAevD,GACxC,kBAAkBmD,EAASC,MASLI,GACtBC,KAAiBD,GACbE,KAAiBF,GACjB,eAAeA,QA+BnB,CACEG,EACAC,EACAC,EAAuB,KAEzB,CAACC,EAAYC,KA+BX,GAzBEA,GACCA,EAAetB,WACfsB,EAAetB,UAAUuB,gBACzBD,EAAetB,UAAUuB,eAAelE,aAGlB2C,UAAUuB,eAAelE,IAK1B0C,EAAMyB,gBAC5BF,EACAjE,EACA,CACEkB,OAAQ2C,EACRO,SAAU3C,GAEZ,CACEP,OAAQ4C,EACRM,SAAUC,EACVC,UAAU,IAIQ,OAGjBnD,MAAMC,QAAQyC,KAEjBA,EAAa,CAACA,IAGhB,aACKnC,EACAoC,IAECxD,gBACJA,EAAeC,gBACfA,EAAeC,eACfA,EAAcC,aACdA,EAAYI,QACZA,EAAOE,WACPA,EAAUC,YACVA,EAAWN,gBACXA,EAAeC,gBACfA,GACE4D,aD+MNvD,EACAD,EACAyD,GAKA,GAA2B,qBACzB,SAGF,GAA2B,mBAAU,CACnC,MAEA,IACEC,EAAqBC,QAAQC,QAAQ3D,GACrC,MAAOkC,GACPuB,EAAqBC,QAAQC,QAC3BC,EAAKzC,KAAK0C,QAAQC,MAAO9D,IAK7B,eAAeyD,GAUjB,OAPK1D,GAAcyD,GAEjBO,QAAQC,6EACkEhF,WC3O5CiF,CAC5BjE,EACAD,EACAgD,EAAQmB,OA4B2B1E,EAAiB,GAAK,OACxBC,EAAe,GAAK,KACvD,MAEA,GAAIH,EAAiB,CACnB,QAAuC,GACvC0D,EAAKmB,YAAY,QAAUC,IACzB,MAAMC,OAAEA,GAAWD,IACNC,EAAOC,MAAM,KAAK,GAAGC,OAElCC,EAAqBC,KAAKC,KAG5BC,EAAkB,oBAAoBH,EAAqBrD,KAAK,UAIlE0B,EAAW+B,QAAStD,IAClB,MAAkCA,EA8ElC,WACEuD,EACAC,EACAC,EACAC,GAAa,GAEb,MAAQ9F,MAAO+F,EAAWC,KAAMC,GAAaN,IAC/BE,GAAiBE,EAG/B,OAAe,KACC,KACG,KACF,EA6BjB,GA1BI3F,GAEqB8F,EACrB9F,EACAgC,KAIA+D,EAAWC,EAAMlD,KAAKlD,IAAUyF,EAAgBvC,KAAKlD,IAKrDK,IAAoB8F,GAECD,EACrB7F,EACA+B,KAIAiE,EAAYC,EAAOpD,KAAKlD,IAM1B8F,KACE1F,GAAoBA,IAAoB+F,MACxC9F,GAAoBA,IAAoBgG,KACO,IA5SrC,EAACL,EAAchG,IAClCuG,EAAYrD,KAAK8C,IAAmB,gBAAVhG,GAC3BoG,EAAMlD,KAAKlD,IACXsG,EAAOpD,KAAKlD,IACZwG,EAAUR,EAAMhG,GAwSRyG,CAAcb,EAAeC,GAE7B,SAIF,GAAIvF,KAAoB6F,IAAaE,GAAY,CAC/C,MAAgBK,EAAYtE,GAE5B,IAAKuE,EAAW,CACd,QAAsBC,EAAmBtG,EAAgB8B,GAErDyE,IACFF,EAAY,eAAeE,EAAc5E,KAAK,WAC9CyE,EAAYtE,GAAYuE,GAIxBA,IACFG,EAAeH,EAAUzD,KAAKlD,IAIlC,GAAIO,KAAkB4F,IAAaE,IAAcS,GAAe,CAC9D,MAAkBC,EAAU3E,GAE5B,IAAK4E,EAAa,CAChB,QAAoBC,EAAiB1G,EAAc6B,GAE/CoB,IACFwD,EAAcxD,EAAY0D,IAAIC,GAC9BJ,EAAU3E,GAAY4E,GAItBA,IACFI,EACEJ,EAAYK,OAAQC,GAAYA,EAAQpE,KAAKlD,IAAQgC,OAAS,GAKpE,KAAKmE,GAAaE,GAAcS,GAAiBM,GAAY,CAC3D,QDvIV,SACE/C,EACAjC,GAEA,MAAMhC,gBAAEA,EAAeC,gBAAEA,EAAeC,eAAEA,EAAcC,aAAEA,GACxD8D,IAC2B,GAsB7B,OApBIjE,GACFyB,EAAM0D,KAAK,YAGTlF,GACFwB,EAAM0D,KAAK,YAGTjF,GAAkBsG,EAAmBtG,EAAgB8B,IACvDP,EAAM0D,KAAK,YAImB,IAA9B1D,EAAMH,QAAQ,YACdnB,GACA0G,EAAiB1G,EAAc6B,IAE/BP,EAAM0D,KAAK,aC8GSgC,CAASlD,EAAQjC,GAG/B,GAAIyB,EAAQmB,MAAQnE,GAAc2G,EAChC,IACE,QAAmBA,EACjB7B,EACA,CACEQ,SAAAA,EACAE,UAAAA,EACAS,aAAAA,EACAM,WAAAA,EACAxB,aAAAA,EACAC,cAAAA,GAEF/B,EACAO,GAIEoD,IAEF9B,EAAK3F,MAAQyH,GAEf,MAAOzE,GACP,MAAM0E,KAAEA,GAAS/B,IAEHA,EAAKgC,OAAQC,MAE3BpF,EAAMqF,OAAO,CACX/H,SAAAA,EACAiE,OAAAA,EACA4B,KAAAA,EACAmC,KAAMF,EAAOE,KACbC,OAAQH,EAAOG,OAAS9B,EAASjE,OAAS0F,EAAKM,QAAShG,OACxDrB,QAASsH,EAASlF,YAAYC,EAAOhD,EAAOiG,SAG3C,CACL,MAAMyB,KAAEA,GAAS/B,IAEHA,EAAKgC,OAAQC,MAE3BpF,EAAMqF,OAAO,CACX/H,SAAAA,EACAiE,OAAAA,EACA4B,KAAAA,EACAmC,KAAMF,EAAOE,KACbC,OAAQH,EAAOG,OAAS9B,EAASjE,OAAS0F,EAAKM,QAAShG,OACxDrB,QAASA,EACLsH,EAASrF,eACPsF,EAAcrG,GACd7B,EACAiG,EACAtF,GAEFsH,EAAStF,SAASuF,EAAcrG,GAAQ7B,EAAOiG,KAIvD,SAGF,SAnOExC,EAAc0E,KAChBA,EAAazE,EAAcyE,IAI7BrE,EAAKsE,UAQL,SAAoBzC,GAClB,MAAM3F,MAAEA,EAAKgG,KAAEA,GAASL,EAGxB,GAAI0C,EAAWnF,KAAK8C,GAAO,OAE3B,QAAoBxF,GAAmB8H,EAASC,YAAYvC,GAE5D,GACEA,IAASmC,IACPK,GACAL,qBACAA,EAAWjF,KAAK8C,GAClB,CACA,QAAyByC,EAAKC,MAAM1I,GAGpC,GAAIuC,EAAOP,OAAS,EAAG,CACrB,OAAiB,EAEjBO,EAAOmD,QAASiD,IACTC,IACHA,EAAaC,EAAoBlD,EAAMK,EAAM2C,WAIjDE,EAAoBlD,WAEb6C,EAAa,CACtB,QAAsBF,EAASQ,OAAO9C,EAAMhG,EAAOS,GACnD,OAAiB,EAEjBR,OAAOqB,KAAKyH,GAAerD,QAASE,IAClC,QAAsBmD,EAAcnD,IAGjCgD,IACAhD,IAAiBuC,GACfA,qBAAgCA,EAAWjF,KAAK0C,MAEnDgD,EAAaC,EACXlD,EACAC,EACAC,GACA,YA+KhBmD,EAAaC,oBAAqB,EAClCD,EAAalJ,SAAWA,EACxBkJ,EAAaf,SAAWA,EAExB,QAAqCxF,EAAUyG,aAC7CpJ,EACAkJ"} -------------------------------------------------------------------------------- /dist/lib/validation.d.ts: -------------------------------------------------------------------------------- 1 | import { SecondaryOptions, IgnoreValue, IgnoreValueList, IgnoreVariableOrFunctionConfig, IgnoreValueConfig, AutoFixFunc, AutoFixFuncConfig } from '../defaults'; 2 | /** 3 | * Validate primary options of stylelint plugin config. 4 | * 5 | * @internal 6 | * @param actual - The actual config to validate. 7 | * 8 | * @returns Returns `true` if primary options are valid, else `false`. 9 | */ 10 | export declare function validProperties(actual: unknown): actual is IgnoreValue | IgnoreValueList; 11 | /** 12 | * Validate optional secondary options of stylelint plugin config. 13 | * 14 | * @internal 15 | * @param actual - The actual config to validate. 16 | * 17 | * @returns Returns `true` if secondary options are valid, else `false`. 18 | */ 19 | export declare function validOptions(actual: SecondaryOptions): boolean; 20 | /** 21 | * Expected type of CSS value, available by configuration. 22 | * @internal 23 | */ 24 | declare type ExpectedType = 'variable' | 'function' | 'keyword'; 25 | /** 26 | * Expected types of CSS value, as configured. 27 | * @internal 28 | */ 29 | declare type ExpectedTypes = Array; 30 | /** 31 | * Build expected message for stylelint report. 32 | * 33 | * @internal 34 | * @param types - Either `variable`, `function` and/or `keyword`. 35 | * 36 | * @returns Returns an expected types message for stylelint report. 37 | */ 38 | export declare function expectedTypes(types: ExpectedType | ExpectedTypes): string; 39 | /** 40 | * Build expected message for stylelint report. 41 | * 42 | * @internal 43 | * @param typesMessage - An expected types message for stylelint report. 44 | * @param value - The CSS declaration's value. 45 | * @param property - The CSS declaration's property. 46 | * 47 | * @returns Returns an expected message for stylelint report. 48 | */ 49 | export declare function expected(typesMessage: string, value: string, property: string): string; 50 | /** 51 | * Build custom expected message for stylelint report. 52 | * 53 | * @internal 54 | * @param typesMessage - An expected types message for stylelint report. 55 | * @param value - The CSS declaration's value. 56 | * @param property - The CSS declaration's property. 57 | * @param customMessage - A custom message to be delivered upon error interpolated with `${types}`, `${value}` and `${property}`. 58 | * 59 | * @returns Returns a custom expected message for stylelint report. 60 | */ 61 | export declare function customExpected(typesMessage: string, value: string, property: string, customMessage: string): string; 62 | /** 63 | * Build failed-to-fix message for stylelint report. 64 | * 65 | * @internal 66 | * @param error - An expression to `throw`. 67 | * @param value - The CSS declaration's value. 68 | * @param property - The CSS declaration's property. 69 | * 70 | * @returns Returns an failed-to-fix message for stylelint report. 71 | */ 72 | export declare function failedToFix(error: unknown, value: string, property: string): string; 73 | /** 74 | * Get configured types for stylelint report message. 75 | * 76 | * @internal 77 | * @param config - The secondary stylelint-plugin config. 78 | * @param property - The specific CSS declaration's property of the current iteration. 79 | * 80 | * @returns Returns a list of configured types. 81 | */ 82 | export declare function getTypes(config: SecondaryOptions, property: string): ExpectedTypes; 83 | /** 84 | * Get the correct ignored variable or function for a specific CSS declaration's property 85 | * out of a complex `ignoreVariablesOrFunctions` config hash or boolean. 86 | * 87 | * @internal 88 | * @param ignoreVariablesOrFunctions - The variables or functions to ignore. 89 | * @param property - The specific CSS declaration's property of the current iteration. 90 | * 91 | * @returns Returns ignored variable or function for a specific CSS property. 92 | */ 93 | export declare function getIgnoredVariablesOrFunctions(ignoreVariablesOrFunctions: IgnoreVariableOrFunctionConfig, property: string): boolean; 94 | /** 95 | * Get the correct ignored keywords for a specific CSS declaration's property 96 | * out of a complex `ignoreKeywords` config hash or array. 97 | * 98 | * @internal 99 | * @param ignoreKeywords - The keyword/-s to ignore. 100 | * @param property - The specific CSS declaration's property of the current iteration. 101 | * 102 | * @returns Returns ignored keywords for a specific CSS property, or `null`. 103 | */ 104 | export declare function getIgnoredKeywords(ignoreKeywords: IgnoreValueConfig, property: string): null | IgnoreValueList; 105 | /** 106 | * Get the correct ignored values for a specific CSS declaration's property 107 | * out of a complex `ignoreValues` config hash or array. 108 | * 109 | * @internal 110 | * @param ignoreValues - The values/-s to ignore. 111 | * @param property - The specific CSS declaration's property of the current iteration. 112 | * @returns Returns ignored values for a specific CSS property, or `null`. 113 | */ 114 | export declare function getIgnoredValues(ignoreValues: IgnoreValueConfig, property: string): null | IgnoreValueList; 115 | /** 116 | * Get the auto-fix function either by a function directly or from a source file. 117 | * 118 | * @internal 119 | * @param autoFixFunc - A JavaScript function or a module path to resolve it, also from `cwd`. 120 | * 121 | * @returns Returns the auto-fix function if found, else `null`. 122 | */ 123 | export declare function getAutoFixFunc(autoFixFunc: AutoFixFuncConfig, disableFix?: boolean, contextFix?: boolean): null | AutoFixFunc; 124 | export {}; 125 | -------------------------------------------------------------------------------- /dist/unsafe-quiet-stylelint-deprecation-warning.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Quiet all stylelint related deprecation warnings like `context.fix` or `utils.report` API. 3 | */ 4 | export default function unsafeQuietStylelintDeprecationWarning(): void; 5 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | stylelint-declaration-strict-value - v1.10.11 2 | 3 | # stylelint-declaration-strict-value - v1.10.11 4 | 5 | ## Table of contents 6 | 7 | ### Modules 8 | 9 | - [defaults](modules/defaults.md) 10 | - [index](modules/index.md) 11 | - [lib/validation](modules/lib_validation.md) 12 | -------------------------------------------------------------------------------- /docs/interfaces/defaults.declarationstrictvalueresult.md: -------------------------------------------------------------------------------- 1 | [stylelint-declaration-strict-value - v1.10.11](../README.md) / [defaults](../modules/defaults.md) / DeclarationStrictValueResult 2 | 3 | # Interface: DeclarationStrictValueResult 4 | 5 | [defaults](../modules/defaults.md).DeclarationStrictValueResult 6 | 7 | Result of CSS value validation. 8 | 9 | ## Table of contents 10 | 11 | ### Properties 12 | 13 | - [longhandProp](defaults.DeclarationStrictValueResult.md#longhandprop) 14 | - [longhandValue](defaults.DeclarationStrictValueResult.md#longhandvalue) 15 | - [validFunc](defaults.DeclarationStrictValueResult.md#validfunc) 16 | - [validKeyword](defaults.DeclarationStrictValueResult.md#validkeyword) 17 | - [validValue](defaults.DeclarationStrictValueResult.md#validvalue) 18 | - [validVar](defaults.DeclarationStrictValueResult.md#validvar) 19 | 20 | ## Properties 21 | 22 | ### longhandProp 23 | 24 | • `Optional` **longhandProp**: `string` 25 | 26 | Longhand CSS Property, if expanded. 27 | 28 | #### Defined in 29 | 30 | [defaults.ts:85](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L85) 31 | 32 | ___ 33 | 34 | ### longhandValue 35 | 36 | • `Optional` **longhandValue**: `string` 37 | 38 | Longhand CSS value, if expanded. 39 | 40 | #### Defined in 41 | 42 | [defaults.ts:90](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L90) 43 | 44 | ___ 45 | 46 | ### validFunc 47 | 48 | • **validFunc**: `boolean` 49 | 50 | Whether or not function is valid. 51 | 52 | #### Defined in 53 | 54 | [defaults.ts:70](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L70) 55 | 56 | ___ 57 | 58 | ### validKeyword 59 | 60 | • **validKeyword**: `boolean` 61 | 62 | Whether or not keyword is valid. 63 | 64 | #### Defined in 65 | 66 | [defaults.ts:75](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L75) 67 | 68 | ___ 69 | 70 | ### validValue 71 | 72 | • **validValue**: `boolean` 73 | 74 | Whether or not value is valid. 75 | 76 | #### Defined in 77 | 78 | [defaults.ts:80](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L80) 79 | 80 | ___ 81 | 82 | ### validVar 83 | 84 | • **validVar**: `boolean` 85 | 86 | Whether or not variable is valid. 87 | 88 | #### Defined in 89 | 90 | [defaults.ts:65](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L65) 91 | -------------------------------------------------------------------------------- /docs/interfaces/defaults.ignorevaluehash.md: -------------------------------------------------------------------------------- 1 | [stylelint-declaration-strict-value - v1.10.11](../README.md) / [defaults](../modules/defaults.md) / IgnoreValueHash 2 | 3 | # Interface: IgnoreValueHash 4 | 5 | [defaults](../modules/defaults.md).IgnoreValueHash 6 | 7 | A hash of CSS properties with ignored values. 8 | - `''` key applies to all configured CSS properties. 9 | - key can also be a Regular Expression string. 10 | 11 | ## Indexable 12 | 13 | ▪ [CSSPropertyName: `string`]: [`IgnoreValue`](../modules/defaults.md#ignorevalue) \| [`IgnoreValueList`](../modules/defaults.md#ignorevaluelist) 14 | 15 | ## Table of contents 16 | 17 | ### Properties 18 | 19 | - [](defaults.IgnoreValueHash.md#) 20 | 21 | ## Properties 22 | 23 | • ****: [`IgnoreValue`](../modules/defaults.md#ignorevalue) \| [`IgnoreValueList`](../modules/defaults.md#ignorevaluelist) 24 | 25 | #### Defined in 26 | 27 | [defaults.ts:38](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L38) 28 | -------------------------------------------------------------------------------- /docs/interfaces/defaults.ignorevariableorfunctionhash.md: -------------------------------------------------------------------------------- 1 | [stylelint-declaration-strict-value - v1.10.11](../README.md) / [defaults](../modules/defaults.md) / IgnoreVariableOrFunctionHash 2 | 3 | # Interface: IgnoreVariableOrFunctionHash 4 | 5 | [defaults](../modules/defaults.md).IgnoreVariableOrFunctionHash 6 | 7 | A hash of CSS properties to ignore variables or functions. 8 | 9 | ## Indexable 10 | 11 | ▪ [key: `string`]: `boolean` 12 | -------------------------------------------------------------------------------- /docs/interfaces/defaults.secondaryoptions.md: -------------------------------------------------------------------------------- 1 | [stylelint-declaration-strict-value - v1.10.11](../README.md) / [defaults](../modules/defaults.md) / SecondaryOptions 2 | 3 | # Interface: SecondaryOptions 4 | 5 | [defaults](../modules/defaults.md).SecondaryOptions 6 | 7 | Plugin secondary options. 8 | 9 | ## Table of contents 10 | 11 | ### Properties 12 | 13 | - [autoFixFunc](defaults.SecondaryOptions.md#autofixfunc) 14 | - [disableFix](defaults.SecondaryOptions.md#disablefix) 15 | - [expandShorthand](defaults.SecondaryOptions.md#expandshorthand) 16 | - [ignoreFunctions](defaults.SecondaryOptions.md#ignorefunctions) 17 | - [ignoreKeywords](defaults.SecondaryOptions.md#ignorekeywords) 18 | - [ignoreValues](defaults.SecondaryOptions.md#ignorevalues) 19 | - [ignoreVariables](defaults.SecondaryOptions.md#ignorevariables) 20 | - [message](defaults.SecondaryOptions.md#message) 21 | - [recurseLonghand](defaults.SecondaryOptions.md#recurselonghand) 22 | - [severity](defaults.SecondaryOptions.md#severity) 23 | 24 | ## Properties 25 | 26 | ### autoFixFunc 27 | 28 | • `Optional` **autoFixFunc**: [`AutoFixFuncConfig`](../modules/defaults.md#autofixfuncconfig) 29 | 30 | By default no auto-fix feature. 31 | 32 | **`defaultvalue`** null 33 | 34 | #### Defined in 35 | 36 | [defaults.ts:183](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L183) 37 | 38 | ___ 39 | 40 | ### disableFix 41 | 42 | • `Optional` **disableFix**: `boolean` 43 | 44 | Don't auto-fix if `--fix` option is applied. 45 | 46 | **`defaultvalue`** false 47 | 48 | #### Defined in 49 | 50 | [defaults.ts:176](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L176) 51 | 52 | ___ 53 | 54 | ### expandShorthand 55 | 56 | • `Optional` **expandShorthand**: `boolean` 57 | 58 | Whether or not to expand shorthand CSS properties. 59 | 60 | **`defaultvalue`** false 61 | 62 | #### Defined in 63 | 64 | [defaults.ts:148](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L148) 65 | 66 | ___ 67 | 68 | ### ignoreFunctions 69 | 70 | • `Optional` **ignoreFunctions**: [`IgnoreVariableOrFunctionConfig`](../modules/defaults.md#ignorevariableorfunctionconfig) 71 | 72 | Whether or not to ignore function. 73 | 74 | **`defaultvalue`** true 75 | 76 | #### Defined in 77 | 78 | [defaults.ts:126](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L126) 79 | 80 | ___ 81 | 82 | ### ignoreKeywords 83 | 84 | • `Optional` **ignoreKeywords**: [`IgnoreValueConfig`](../modules/defaults.md#ignorevalueconfig) 85 | 86 | An ignored keywords config. 87 | 88 | **`defaultvalue`** null 89 | 90 | **`deprecated`** use `ignoreValues` option. 91 | 92 | #### Defined in 93 | 94 | [defaults.ts:134](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L134) 95 | 96 | ___ 97 | 98 | ### ignoreValues 99 | 100 | • `Optional` **ignoreValues**: [`IgnoreValueConfig`](../modules/defaults.md#ignorevalueconfig) 101 | 102 | An ignored values config. 103 | 104 | **`defaultvalue`** null 105 | 106 | #### Defined in 107 | 108 | [defaults.ts:141](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L141) 109 | 110 | ___ 111 | 112 | ### ignoreVariables 113 | 114 | • `Optional` **ignoreVariables**: [`IgnoreVariableOrFunctionConfig`](../modules/defaults.md#ignorevariableorfunctionconfig) 115 | 116 | Whether or not to ignore variables. 117 | 118 | **`defaultvalue`** true 119 | 120 | #### Defined in 121 | 122 | [defaults.ts:119](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L119) 123 | 124 | ___ 125 | 126 | ### message 127 | 128 | • `Optional` **message**: `string` 129 | 130 | A custom message when a rule is violated, interpolated with `${types}`, `${value}` and `${property}`. 131 | 132 | **`defaultvalue`** undefined 133 | 134 | #### Defined in 135 | 136 | [defaults.ts:169](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L169) 137 | 138 | ___ 139 | 140 | ### recurseLonghand 141 | 142 | • `Optional` **recurseLonghand**: `boolean` 143 | 144 | Whether or not to expand longhand CSS properties recursivly - this is only useful for the `border` property. 145 | 146 | **`defaultvalue`** false 147 | 148 | #### Defined in 149 | 150 | [defaults.ts:155](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L155) 151 | 152 | ___ 153 | 154 | ### severity 155 | 156 | • `Optional` **severity**: `string` 157 | 158 | Adjust severity of the rule, `'warning'` or `'error'` (default). 159 | 160 | **`defaultvalue`** 'error' 161 | 162 | #### Defined in 163 | 164 | [defaults.ts:162](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L162) 165 | -------------------------------------------------------------------------------- /docs/modules/defaults.md: -------------------------------------------------------------------------------- 1 | [stylelint-declaration-strict-value - v1.10.11](../README.md) / defaults 2 | 3 | # Module: defaults 4 | 5 | ## Table of contents 6 | 7 | ### Interfaces 8 | 9 | - [DeclarationStrictValueResult](../interfaces/defaults.DeclarationStrictValueResult.md) 10 | - [IgnoreValueHash](../interfaces/defaults.IgnoreValueHash.md) 11 | - [IgnoreVariableOrFunctionHash](../interfaces/defaults.IgnoreVariableOrFunctionHash.md) 12 | - [SecondaryOptions](../interfaces/defaults.SecondaryOptions.md) 13 | 14 | ### Type aliases 15 | 16 | - [AutoFixFunc](defaults.md#autofixfunc) 17 | - [AutoFixFuncConfig](defaults.md#autofixfuncconfig) 18 | - [AutoFixModule](defaults.md#autofixmodule) 19 | - [IgnoreValue](defaults.md#ignorevalue) 20 | - [IgnoreValueConfig](defaults.md#ignorevalueconfig) 21 | - [IgnoreValueList](defaults.md#ignorevaluelist) 22 | - [IgnoreVariableOrFunctionConfig](defaults.md#ignorevariableorfunctionconfig) 23 | - [RegExpString](defaults.md#regexpstring) 24 | 25 | ### Variables 26 | 27 | - [default](defaults.md#default) 28 | - [ruleName](defaults.md#rulename) 29 | 30 | ### Functions 31 | 32 | - [isIIgnoreValueHash](defaults.md#isiignorevaluehash) 33 | 34 | ## Type aliases 35 | 36 | ### AutoFixFunc 37 | 38 | Ƭ **AutoFixFunc**: (`node`: `Node`, `result`: [`DeclarationStrictValueResult`](../interfaces/defaults.DeclarationStrictValueResult.md), `root`: `Root`, `config`: [`SecondaryOptions`](../interfaces/defaults.SecondaryOptions.md)) => `string` 39 | 40 | #### Type declaration 41 | 42 | ▸ (`node`, `result`, `root`, `config`): `string` 43 | 44 | A autofix function. 45 | 46 | ##### Parameters 47 | 48 | | Name | Type | 49 | | :------ | :------ | 50 | | `node` | `Node` | 51 | | `result` | [`DeclarationStrictValueResult`](../interfaces/defaults.DeclarationStrictValueResult.md) | 52 | | `root` | `Root` | 53 | | `config` | [`SecondaryOptions`](../interfaces/defaults.SecondaryOptions.md) | 54 | 55 | ##### Returns 56 | 57 | `string` 58 | 59 | #### Defined in 60 | 61 | [defaults.ts:95](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L95) 62 | 63 | ___ 64 | 65 | ### AutoFixFuncConfig 66 | 67 | Ƭ **AutoFixFuncConfig**: ``null`` \| `undefined` \| [`AutoFixModule`](defaults.md#autofixmodule) \| [`AutoFixFunc`](defaults.md#autofixfunc) 68 | 69 | Possible config for `autoFixFunc` option. 70 | 71 | #### Defined in 72 | 73 | [defaults.ts:108](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L108) 74 | 75 | ___ 76 | 77 | ### AutoFixModule 78 | 79 | Ƭ **AutoFixModule**: `string` 80 | 81 | Path to autofix function module. 82 | 83 | #### Defined in 84 | 85 | [defaults.ts:104](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L104) 86 | 87 | ___ 88 | 89 | ### IgnoreValue 90 | 91 | Ƭ **IgnoreValue**: `number` \| `string` \| [`RegExpString`](defaults.md#regexpstring) 92 | 93 | A CSS value to be ignored. 94 | 95 | #### Defined in 96 | 97 | [defaults.ts:27](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L27) 98 | 99 | ___ 100 | 101 | ### IgnoreValueConfig 102 | 103 | Ƭ **IgnoreValueConfig**: ``null`` \| [`IgnoreValue`](defaults.md#ignorevalue) \| [`IgnoreValueList`](defaults.md#ignorevaluelist) \| [`IgnoreValueHash`](../interfaces/defaults.IgnoreValueHash.md) 104 | 105 | Possible config for `ignoreValues` and ~~`ignoreKeywords`~~ option. 106 | 107 | #### Defined in 108 | 109 | [defaults.ts:53](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L53) 110 | 111 | ___ 112 | 113 | ### IgnoreValueList 114 | 115 | Ƭ **IgnoreValueList**: [`IgnoreValue`](defaults.md#ignorevalue)[] 116 | 117 | A list of CSS values to be ignored. 118 | 119 | #### Defined in 120 | 121 | [defaults.ts:31](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L31) 122 | 123 | ___ 124 | 125 | ### IgnoreVariableOrFunctionConfig 126 | 127 | Ƭ **IgnoreVariableOrFunctionConfig**: `boolean` \| [`IgnoreVariableOrFunctionHash`](../interfaces/defaults.IgnoreVariableOrFunctionHash.md) 128 | 129 | Possible config for `ignoreVariables` and `ignoreFunctions` option. 130 | 131 | #### Defined in 132 | 133 | [defaults.ts:17](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L17) 134 | 135 | ___ 136 | 137 | ### RegExpString 138 | 139 | Ƭ **RegExpString**: `string` 140 | 141 | A Regular Expression string to match a CSS property or value. 142 | 143 | #### Defined in 144 | 145 | [defaults.ts:23](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L23) 146 | 147 | ## Variables 148 | 149 | ### default 150 | 151 | • **default**: [`SecondaryOptions`](../interfaces/defaults.SecondaryOptions.md) 152 | 153 | #### Defined in 154 | 155 | [defaults.ts:186](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L186) 156 | 157 | ___ 158 | 159 | ### ruleName 160 | 161 | • **ruleName**: ``"scale-unlimited/declaration-strict-value"`` 162 | 163 | Rule Name. 164 | 165 | #### Defined in 166 | 167 | [defaults.ts:6](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L6) 168 | 169 | ## Functions 170 | 171 | ### isIIgnoreValueHash 172 | 173 | ▸ `Const` **isIIgnoreValueHash**(`key`, `value`): key is IgnoreValueHash 174 | 175 | **`internal`** 176 | 177 | #### Parameters 178 | 179 | | Name | Type | 180 | | :------ | :------ | 181 | | `key` | `unknown` | 182 | | `value` | `unknown` | 183 | 184 | #### Returns 185 | 186 | key is IgnoreValueHash 187 | 188 | #### Defined in 189 | 190 | [defaults.ts:45](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/defaults.ts#L45) 191 | -------------------------------------------------------------------------------- /docs/modules/index.md: -------------------------------------------------------------------------------- 1 | [stylelint-declaration-strict-value - v1.10.11](../README.md) / index 2 | 3 | # Module: index 4 | 5 | ## Table of contents 6 | 7 | ### References 8 | 9 | - [ruleName](index.md#rulename) 10 | 11 | ### Namespaces 12 | 13 | - [rule](index.rule.md) 14 | 15 | ### Variables 16 | 17 | - [default](index.md#default) 18 | - [messages](index.md#messages) 19 | - [meta](index.md#meta) 20 | - [rule](index.md#rule) 21 | 22 | ## References 23 | 24 | ### ruleName 25 | 26 | Re-exports [ruleName](defaults.md#rulename) 27 | 28 | ## Variables 29 | 30 | ### default 31 | 32 | • **default**: `Plugin` 33 | 34 | #### Defined in 35 | 36 | [index.ts:504](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/index.ts#L504) 37 | 38 | ___ 39 | 40 | ### messages 41 | 42 | • **messages**: `Object` 43 | 44 | #### Type declaration 45 | 46 | | Name | Type | 47 | | :------ | :------ | 48 | | `customExpected` | (`typesMessage`: `string`, `value`: `string`, `property`: `string`, `customMessage`: `string`) => `string` | 49 | | `expected` | (`typesMessage`: `string`, `value`: `string`, `property`: `string`) => `string` | 50 | | `failedToFix` | (`error`: `unknown`, `value`: `string`, `property`: `string`) => `string` | 51 | 52 | #### Defined in 53 | 54 | [index.ts:38](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/index.ts#L38) 55 | 56 | ___ 57 | 58 | ### meta 59 | 60 | • **meta**: `RuleMeta` 61 | 62 | #### Defined in 63 | 64 | [index.ts:34](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/index.ts#L34) 65 | 66 | ___ 67 | 68 | ### rule 69 | 70 | • **rule**: `StylelintPlugin`<`PrimaryOptions`, [`SecondaryOptions`](../interfaces/defaults.SecondaryOptions.md)\> 71 | 72 | #### Defined in 73 | 74 | [index.ts:155](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/index.ts#L155) 75 | -------------------------------------------------------------------------------- /docs/modules/index.rule.md: -------------------------------------------------------------------------------- 1 | [stylelint-declaration-strict-value - v1.10.11](../README.md) / [index](index.md) / rule 2 | 3 | # Namespace: rule 4 | 5 | [index](index.md).rule 6 | 7 | ## Table of contents 8 | 9 | ### Variables 10 | 11 | - [messages](index.rule.md#messages) 12 | - [meta](index.rule.md#meta) 13 | - [primaryOptionArray](index.rule.md#primaryoptionarray) 14 | - [ruleName](index.rule.md#rulename) 15 | 16 | ## Variables 17 | 18 | ### messages 19 | 20 | • **messages**: `RuleMessages` 21 | 22 | ___ 23 | 24 | ### meta 25 | 26 | • **meta**: `undefined` \| `RuleMeta` 27 | 28 | ___ 29 | 30 | ### primaryOptionArray 31 | 32 | • **primaryOptionArray**: `undefined` \| `boolean` 33 | 34 | ___ 35 | 36 | ### ruleName 37 | 38 | • **ruleName**: `string` 39 | -------------------------------------------------------------------------------- /docs/modules/lib_validation.md: -------------------------------------------------------------------------------- 1 | [stylelint-declaration-strict-value - v1.10.11](../README.md) / lib/validation 2 | 3 | # Module: lib/validation 4 | 5 | ## Table of contents 6 | 7 | ### Functions 8 | 9 | - [customExpected](lib_validation.md#customexpected) 10 | - [expected](lib_validation.md#expected) 11 | - [expectedTypes](lib_validation.md#expectedtypes) 12 | - [failedToFix](lib_validation.md#failedtofix) 13 | - [getAutoFixFunc](lib_validation.md#getautofixfunc) 14 | - [getIgnoredKeywords](lib_validation.md#getignoredkeywords) 15 | - [getIgnoredValues](lib_validation.md#getignoredvalues) 16 | - [getIgnoredVariablesOrFunctions](lib_validation.md#getignoredvariablesorfunctions) 17 | - [getTypes](lib_validation.md#gettypes) 18 | - [validOptions](lib_validation.md#validoptions) 19 | - [validProperties](lib_validation.md#validproperties) 20 | 21 | ## Functions 22 | 23 | ### customExpected 24 | 25 | ▸ **customExpected**(`typesMessage`, `value`, `property`, `customMessage`): `string` 26 | 27 | Build custom expected message for stylelint report. 28 | 29 | **`internal`** 30 | 31 | #### Parameters 32 | 33 | | Name | Type | Description | 34 | | :------ | :------ | :------ | 35 | | `typesMessage` | `string` | An expected types message for stylelint report. | 36 | | `value` | `string` | The CSS declaration's value. | 37 | | `property` | `string` | The CSS declaration's property. | 38 | | `customMessage` | `string` | A custom message to be delivered upon error interpolated with `${types}`, `${value}` and `${property}`. | 39 | 40 | #### Returns 41 | 42 | `string` 43 | 44 | Returns a custom expected message for stylelint report. 45 | 46 | #### Defined in 47 | 48 | [lib/validation.ts:241](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/lib/validation.ts#L241) 49 | 50 | ___ 51 | 52 | ### expected 53 | 54 | ▸ **expected**(`typesMessage`, `value`, `property`): `string` 55 | 56 | Build expected message for stylelint report. 57 | 58 | **`internal`** 59 | 60 | #### Parameters 61 | 62 | | Name | Type | Description | 63 | | :------ | :------ | :------ | 64 | | `typesMessage` | `string` | An expected types message for stylelint report. | 65 | | `value` | `string` | The CSS declaration's value. | 66 | | `property` | `string` | The CSS declaration's property. | 67 | 68 | #### Returns 69 | 70 | `string` 71 | 72 | Returns an expected message for stylelint report. 73 | 74 | #### Defined in 75 | 76 | [lib/validation.ts:222](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/lib/validation.ts#L222) 77 | 78 | ___ 79 | 80 | ### expectedTypes 81 | 82 | ▸ **expectedTypes**(`types`): `string` 83 | 84 | Build expected message for stylelint report. 85 | 86 | **`internal`** 87 | 88 | #### Parameters 89 | 90 | | Name | Type | Description | 91 | | :------ | :------ | :------ | 92 | | `types` | `ExpectedType` \| `ExpectedTypes` | Either `variable`, `function` and/or `keyword`. | 93 | 94 | #### Returns 95 | 96 | `string` 97 | 98 | Returns an expected types message for stylelint report. 99 | 100 | #### Defined in 101 | 102 | [lib/validation.ts:195](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/lib/validation.ts#L195) 103 | 104 | ___ 105 | 106 | ### failedToFix 107 | 108 | ▸ **failedToFix**(`error`, `value`, `property`): `string` 109 | 110 | Build failed-to-fix message for stylelint report. 111 | 112 | **`internal`** 113 | 114 | #### Parameters 115 | 116 | | Name | Type | Description | 117 | | :------ | :------ | :------ | 118 | | `error` | `unknown` | An expression to `throw`. | 119 | | `value` | `string` | The CSS declaration's value. | 120 | | `property` | `string` | The CSS declaration's property. | 121 | 122 | #### Returns 123 | 124 | `string` 125 | 126 | Returns an failed-to-fix message for stylelint report. 127 | 128 | #### Defined in 129 | 130 | [lib/validation.ts:265](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/lib/validation.ts#L265) 131 | 132 | ___ 133 | 134 | ### getAutoFixFunc 135 | 136 | ▸ **getAutoFixFunc**(`autoFixFunc`, `disableFix?`, `contextFix?`): ``null`` \| [`AutoFixFunc`](defaults.md#autofixfunc) 137 | 138 | Get the auto-fix function either by a function directly or from a source file. 139 | 140 | **`internal`** 141 | 142 | #### Parameters 143 | 144 | | Name | Type | Description | 145 | | :------ | :------ | :------ | 146 | | `autoFixFunc` | [`AutoFixFuncConfig`](defaults.md#autofixfuncconfig) | A JavaScript function or a module path to resolve it, also from `cwd`. | 147 | | `disableFix?` | `boolean` | - | 148 | | `contextFix?` | `boolean` | - | 149 | 150 | #### Returns 151 | 152 | ``null`` \| [`AutoFixFunc`](defaults.md#autofixfunc) 153 | 154 | Returns the auto-fix function if found, else `null`. 155 | 156 | #### Defined in 157 | 158 | [lib/validation.ts:410](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/lib/validation.ts#L410) 159 | 160 | ___ 161 | 162 | ### getIgnoredKeywords 163 | 164 | ▸ **getIgnoredKeywords**(`ignoreKeywords`, `property`): ``null`` \| [`IgnoreValueList`](defaults.md#ignorevaluelist) 165 | 166 | Get the correct ignored keywords for a specific CSS declaration's property 167 | out of a complex `ignoreKeywords` config hash or array. 168 | 169 | **`internal`** 170 | 171 | #### Parameters 172 | 173 | | Name | Type | Description | 174 | | :------ | :------ | :------ | 175 | | `ignoreKeywords` | [`IgnoreValueConfig`](defaults.md#ignorevalueconfig) | The keyword/-s to ignore. | 176 | | `property` | `string` | The specific CSS declaration's property of the current iteration. | 177 | 178 | #### Returns 179 | 180 | ``null`` \| [`IgnoreValueList`](defaults.md#ignorevaluelist) 181 | 182 | Returns ignored keywords for a specific CSS property, or `null`. 183 | 184 | #### Defined in 185 | 186 | [lib/validation.ts:359](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/lib/validation.ts#L359) 187 | 188 | ___ 189 | 190 | ### getIgnoredValues 191 | 192 | ▸ **getIgnoredValues**(`ignoreValues`, `property`): ``null`` \| [`IgnoreValueList`](defaults.md#ignorevaluelist) 193 | 194 | Get the correct ignored values for a specific CSS declaration's property 195 | out of a complex `ignoreValues` config hash or array. 196 | 197 | **`internal`** 198 | 199 | #### Parameters 200 | 201 | | Name | Type | Description | 202 | | :------ | :------ | :------ | 203 | | `ignoreValues` | [`IgnoreValueConfig`](defaults.md#ignorevalueconfig) | The values/-s to ignore. | 204 | | `property` | `string` | The specific CSS declaration's property of the current iteration. | 205 | 206 | #### Returns 207 | 208 | ``null`` \| [`IgnoreValueList`](defaults.md#ignorevaluelist) 209 | 210 | Returns ignored values for a specific CSS property, or `null`. 211 | 212 | #### Defined in 213 | 214 | [lib/validation.ts:385](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/lib/validation.ts#L385) 215 | 216 | ___ 217 | 218 | ### getIgnoredVariablesOrFunctions 219 | 220 | ▸ **getIgnoredVariablesOrFunctions**(`ignoreVariablesOrFunctions`, `property`): `boolean` 221 | 222 | Get the correct ignored variable or function for a specific CSS declaration's property 223 | out of a complex `ignoreVariablesOrFunctions` config hash or boolean. 224 | 225 | **`internal`** 226 | 227 | #### Parameters 228 | 229 | | Name | Type | Description | 230 | | :------ | :------ | :------ | 231 | | `ignoreVariablesOrFunctions` | [`IgnoreVariableOrFunctionConfig`](defaults.md#ignorevariableorfunctionconfig) | The variables or functions to ignore. | 232 | | `property` | `string` | The specific CSS declaration's property of the current iteration. | 233 | 234 | #### Returns 235 | 236 | `boolean` 237 | 238 | Returns ignored variable or function for a specific CSS property. 239 | 240 | #### Defined in 241 | 242 | [lib/validation.ts:327](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/lib/validation.ts#L327) 243 | 244 | ___ 245 | 246 | ### getTypes 247 | 248 | ▸ **getTypes**(`config`, `property`): `ExpectedTypes` 249 | 250 | Get configured types for stylelint report message. 251 | 252 | **`internal`** 253 | 254 | #### Parameters 255 | 256 | | Name | Type | Description | 257 | | :------ | :------ | :------ | 258 | | `config` | [`SecondaryOptions`](../interfaces/defaults.SecondaryOptions.md) | The secondary stylelint-plugin config. | 259 | | `property` | `string` | The specific CSS declaration's property of the current iteration. | 260 | 261 | #### Returns 262 | 263 | `ExpectedTypes` 264 | 265 | Returns a list of configured types. 266 | 267 | #### Defined in 268 | 269 | [lib/validation.ts:286](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/lib/validation.ts#L286) 270 | 271 | ___ 272 | 273 | ### validOptions 274 | 275 | ▸ **validOptions**(`actual`): `boolean` 276 | 277 | Validate optional secondary options of stylelint plugin config. 278 | 279 | **`internal`** 280 | 281 | #### Parameters 282 | 283 | | Name | Type | Description | 284 | | :------ | :------ | :------ | 285 | | `actual` | [`SecondaryOptions`](../interfaces/defaults.SecondaryOptions.md) | The actual config to validate. | 286 | 287 | #### Returns 288 | 289 | `boolean` 290 | 291 | Returns `true` if secondary options are valid, else `false`. 292 | 293 | #### Defined in 294 | 295 | [lib/validation.ts:93](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/lib/validation.ts#L93) 296 | 297 | ___ 298 | 299 | ### validProperties 300 | 301 | ▸ **validProperties**(`actual`): actual is IgnoreValue \| IgnoreValueList 302 | 303 | Validate primary options of stylelint plugin config. 304 | 305 | **`internal`** 306 | 307 | #### Parameters 308 | 309 | | Name | Type | Description | 310 | | :------ | :------ | :------ | 311 | | `actual` | `unknown` | The actual config to validate. | 312 | 313 | #### Returns 314 | 315 | actual is IgnoreValue \| IgnoreValueList 316 | 317 | Returns `true` if primary options are valid, else `false`. 318 | 319 | #### Defined in 320 | 321 | [lib/validation.ts:39](https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/04ca265/src/lib/validation.ts#L39) 322 | -------------------------------------------------------------------------------- /jest.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "preset": "jest-preset-stylelint", 3 | "setupFiles": ["./jest.setup.js"], 4 | "testMatch": ["**/test/*.js"] 5 | } 6 | -------------------------------------------------------------------------------- /jest.coverage.config.js: -------------------------------------------------------------------------------- 1 | const baseConfig = require('./jest.config.json'); 2 | 3 | /** @type {import('jest').Config} */ 4 | const config = { 5 | ...baseConfig, 6 | collectCoverage: true, 7 | coverageReporters: ['lcov', 'text'], 8 | coverageDirectory: '/coverage', 9 | }; 10 | 11 | module.exports = config; 12 | -------------------------------------------------------------------------------- /jest.setup.js: -------------------------------------------------------------------------------- 1 | import { getTestRule } from 'jest-preset-stylelint'; 2 | import { lint } from 'stylelint'; 3 | // eslint-disable-next-line import/extensions 4 | import declarationStrictValuePlugin from './src/index.ts'; 5 | 6 | const plugins = [declarationStrictValuePlugin]; 7 | 8 | global.testRule = getTestRule({ plugins }); 9 | 10 | global.testCustomAutoFixMessage = testCustomAutoFixMessage; 11 | 12 | function testCustomAutoFixMessage({ ruleName, config, reject, fix }) { 13 | // eslint-disable-next-line no-undef 14 | describe(ruleName, () => { 15 | // eslint-disable-next-line no-undef 16 | it('warn for invalid options', async () => { 17 | const rejections = await Promise.all( 18 | reject.map(async ({ code, message }) => { 19 | const { 20 | results: [{ warnings }], 21 | } = await lint({ 22 | fix, 23 | code, 24 | config: { 25 | plugins, 26 | rules: { 27 | [ruleName]: config, 28 | }, 29 | }, 30 | quietDeprecationWarnings: true, 31 | }); 32 | 33 | return { message, warnings }; 34 | }) 35 | ); 36 | 37 | rejections.forEach(({ message, warnings }) => { 38 | const expectedWarning = { 39 | text: message, 40 | }; 41 | 42 | // eslint-disable-next-line no-undef 43 | expect(warnings[0]).toMatchObject(expectedWarning); 44 | }); 45 | }); 46 | }); 47 | } 48 | -------------------------------------------------------------------------------- /lint-staged.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | '(src|test)/**/*.[tj]s': (filenames) => [ 3 | `eslint --fix ${filenames.join(' ')}`, 4 | 'cross-env NODE_OPTIONS="--experimental-vm-modules --no-warnings" jest', 5 | ], 6 | '(README).md': ["doctoc --title '**Table of Contents**'"], 7 | }; 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stylelint-declaration-strict-value", 3 | "version": "1.10.11", 4 | "description": "Specify properties for which a variable, function, keyword or value must be used", 5 | "source": "src/index.ts", 6 | "exports": { 7 | "types": "./dist/index.d.ts", 8 | "require": "./dist/index.js", 9 | "default": "./dist/index.modern.mjs" 10 | }, 11 | "main": "dist/index.js", 12 | "module": "dist/index.esm.js", 13 | "unpkg": "dist/index.umd.js", 14 | "types": "dist/index.d.ts", 15 | "engines": { 16 | "node": ">=18.12.0" 17 | }, 18 | "scripts": { 19 | "build": "microbundle --tsconfig tsconfig.build.json --compress", 20 | "release": "dotenv semantic-release", 21 | "test": "cross-env NODE_OPTIONS=\"--experimental-vm-modules --no-warnings\" jest", 22 | "coverage": "jest --config='./jest.coverage.config.js'", 23 | "postcoverage": "dotenv codecov", 24 | "eslint": "eslint 'src/**/*.[tj]s' 'test/**/*.[tj]s'", 25 | "docs": "typedoc --plugin typedoc-plugin-markdown", 26 | "toc": "doctoc README.md --title '**Table of Contents**'", 27 | "postinstall": "husky install", 28 | "prepublishOnly": "pinst --disable", 29 | "postpublish": "pinst --enable" 30 | }, 31 | "repository": { 32 | "type": "git", 33 | "url": "git+https://github.com/AndyOGo/stylelint-declaration-strict-value.git" 34 | }, 35 | "keywords": [ 36 | "stylelint-plugin", 37 | "stylelint", 38 | "css", 39 | "scss", 40 | "less", 41 | "lint", 42 | "delaration-strict-value", 43 | "variable", 44 | "function", 45 | "keyword", 46 | "color", 47 | "z-index" 48 | ], 49 | "author": "Andreas Deuschlinger", 50 | "license": "MIT", 51 | "bugs": { 52 | "url": "https://github.com/AndyOGo/stylelint-declaration-strict-value/issues" 53 | }, 54 | "homepage": "https://github.com/AndyOGo/stylelint-declaration-strict-value#readme", 55 | "peerDependencies": { 56 | "stylelint": ">=7 <=16" 57 | }, 58 | "devDependencies": { 59 | "@babel/cli": "^7.12.8", 60 | "@babel/core": "^7.20.12", 61 | "@babel/node": "^7.12.6", 62 | "@babel/plugin-proposal-class-properties": "^7.12.1", 63 | "@babel/plugin-proposal-object-rest-spread": "^7.12.1", 64 | "@babel/plugin-transform-destructuring": "^7.12.1", 65 | "@babel/plugin-transform-object-assign": "^7.12.1", 66 | "@babel/preset-env": "^7.20.2", 67 | "@babel/preset-typescript": "^7.18.6", 68 | "@babel/register": "^7.12.1", 69 | "@commitlint/cli": "^12.0.0", 70 | "@commitlint/config-conventional": "^12.0.0", 71 | "@semantic-release/changelog": "^5.0.1", 72 | "@semantic-release/exec": "^5.0.0", 73 | "@semantic-release/git": "^9.0.0", 74 | "@typescript-eslint/eslint-plugin": "^4.8.2", 75 | "@typescript-eslint/parser": "^4.8.2", 76 | "babel-jest": "^29.4.2", 77 | "babel-register-ts": "^7.0.0", 78 | "codecov": "^3.8.1", 79 | "cross-env": "^7.0.3", 80 | "css-values": "^0.1.0", 81 | "doctoc": "^2.0.0", 82 | "dotenv-cli": "^4.0.0", 83 | "eslint": "^7.14.0", 84 | "eslint-config-airbnb-typescript": "^12.0.0", 85 | "eslint-config-prettier": "^8.1.0", 86 | "eslint-plugin-import": "^2.22.1", 87 | "eslint-plugin-jest": "^24.7.0", 88 | "eslint-plugin-prettier": "^3.1.4", 89 | "eslint-plugin-tsdoc": "^0.2.7", 90 | "husky": "^6.0.0", 91 | "jest": "^29.4.2", 92 | "jest-preset-stylelint": "^7.0.0", 93 | "lint-staged": "^10.5.2", 94 | "microbundle": "^0.15.1", 95 | "nyc": "^15.1.0", 96 | "pinst": "^2.1.6", 97 | "prettier": "^2.2.1", 98 | "semantic-release": "^17.3.0", 99 | "shortcss": "^0.1.3", 100 | "stylelint": "^16.1.0", 101 | "typedoc": "^0.22.7", 102 | "typedoc-plugin-markdown": "^3.2.1", 103 | "typescript": "^4.1.2" 104 | }, 105 | "files": [ 106 | "dist" 107 | ] 108 | } 109 | -------------------------------------------------------------------------------- /src/defaults.ts: -------------------------------------------------------------------------------- 1 | import type { Node, Root } from 'postcss'; 2 | 3 | /** 4 | * Rule Name. 5 | */ 6 | export const ruleName = 'scale-unlimited/declaration-strict-value'; 7 | 8 | /** 9 | * A hash of CSS properties to ignore variables or functions. 10 | */ 11 | export interface IgnoreVariableOrFunctionHash { 12 | [key: string]: boolean; 13 | } 14 | /** 15 | * Possible config for `ignoreVariables` and `ignoreFunctions` option. 16 | */ 17 | export type IgnoreVariableOrFunctionConfig = 18 | | boolean 19 | | IgnoreVariableOrFunctionHash; 20 | /** 21 | * A Regular Expression string to match a CSS property or value. 22 | */ 23 | export type RegExpString = string; 24 | /** 25 | * A CSS value to be ignored. 26 | */ 27 | export type IgnoreValue = number | string | RegExpString; 28 | /** 29 | * A list of CSS values to be ignored. 30 | */ 31 | export type IgnoreValueList = Array; 32 | /** 33 | * A hash of CSS properties with ignored values. 34 | * - `''` key applies to all configured CSS properties. 35 | * - key can also be a Regular Expression string. 36 | */ 37 | export interface IgnoreValueHash { 38 | '': IgnoreValue | IgnoreValueList; 39 | [CSSPropertyName: string]: IgnoreValue | IgnoreValueList; 40 | // [CSSPropertyName: TRegExpString]: TIgnoreValue | TIgnoreValueList; 41 | } 42 | /** 43 | * @internal 44 | */ 45 | export const isIIgnoreValueHash = ( 46 | key: unknown, 47 | value: unknown 48 | ): key is IgnoreValueHash => 49 | typeof key === 'object' && Object.hasOwnProperty.call(key, value); 50 | /** 51 | * Possible config for `ignoreValues` and ~~`ignoreKeywords`~~ option. 52 | */ 53 | export type IgnoreValueConfig = 54 | | null 55 | | IgnoreValue 56 | | IgnoreValueList 57 | | IgnoreValueHash; 58 | /** 59 | * Result of CSS value validation. 60 | */ 61 | export interface DeclarationStrictValueResult { 62 | /** 63 | * Whether or not variable is valid. 64 | */ 65 | validVar: boolean; 66 | 67 | /** 68 | * Whether or not function is valid. 69 | */ 70 | validFunc: boolean; 71 | 72 | /** 73 | * Whether or not keyword is valid. 74 | */ 75 | validKeyword: boolean; 76 | 77 | /** 78 | * Whether or not value is valid. 79 | */ 80 | validValue: boolean; 81 | 82 | /** 83 | * Longhand CSS Property, if expanded. 84 | */ 85 | longhandProp?: string; 86 | 87 | /** 88 | * Longhand CSS value, if expanded. 89 | */ 90 | longhandValue?: string; 91 | } 92 | /** 93 | * A autofix function. 94 | */ 95 | export type AutoFixFunc = ( 96 | node: Node, 97 | result: DeclarationStrictValueResult, 98 | root: Root, 99 | config: SecondaryOptions 100 | ) => string; 101 | /** 102 | * Path to autofix function module. 103 | */ 104 | export type AutoFixModule = string; 105 | /** 106 | * Possible config for `autoFixFunc` option. 107 | */ 108 | export type AutoFixFuncConfig = null | undefined | AutoFixModule | AutoFixFunc; 109 | 110 | /** 111 | * Plugin secondary options. 112 | */ 113 | export interface SecondaryOptions { 114 | /** 115 | * Whether or not to ignore variables. 116 | * 117 | * @defaultValue true 118 | */ 119 | ignoreVariables?: IgnoreVariableOrFunctionConfig; 120 | 121 | /** 122 | * Whether or not to ignore function. 123 | * 124 | * @defaultValue true 125 | */ 126 | ignoreFunctions?: IgnoreVariableOrFunctionConfig; 127 | 128 | /** 129 | * An ignored keywords config. 130 | * 131 | * @defaultValue null 132 | * @deprecated use `ignoreValues` option. 133 | */ 134 | ignoreKeywords?: IgnoreValueConfig; 135 | 136 | /** 137 | * An ignored values config. 138 | * 139 | * @defaultValue null 140 | */ 141 | ignoreValues?: IgnoreValueConfig; 142 | 143 | /** 144 | * Whether or not to expand shorthand CSS properties. 145 | * 146 | * @defaultValue false 147 | */ 148 | expandShorthand?: boolean; 149 | 150 | /** 151 | * Whether or not to expand longhand CSS properties recursivly - this is only useful for the `border` property. 152 | * 153 | * @defaultValue false 154 | */ 155 | recurseLonghand?: boolean; 156 | 157 | /** 158 | * Adjust severity of the rule, `'warning'` or `'error'` (default). 159 | * 160 | * @defaultValue 'error' 161 | */ 162 | severity?: string; 163 | 164 | /** 165 | * A custom message when a rule is violated, interpolated with `${types}`, `${value}` and `${property}`. 166 | * 167 | * @defaultValue undefined 168 | */ 169 | message?: string; 170 | 171 | /** 172 | * Don't auto-fix if `--fix` option is applied. 173 | * 174 | * @defaultValue false 175 | */ 176 | disableFix?: boolean; 177 | 178 | /** 179 | * By default no auto-fix feature. 180 | * 181 | * @defaultValue null 182 | */ 183 | autoFixFunc?: AutoFixFuncConfig; 184 | } 185 | 186 | const defaults: SecondaryOptions = { 187 | ignoreVariables: true, 188 | ignoreFunctions: true, 189 | ignoreKeywords: null, 190 | ignoreValues: null, 191 | expandShorthand: false, 192 | recurseLonghand: false, 193 | severity: 'error', 194 | message: undefined, 195 | disableFix: false, 196 | autoFixFunc: null, 197 | }; 198 | 199 | export default defaults; 200 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import type { Declaration, Root, AtRule } from 'postcss'; 2 | import stylelint, { PostcssResult, Rule, RuleMeta } from 'stylelint'; 3 | // eslint-disable-next-line import/no-extraneous-dependencies 4 | import shortCSS from 'shortcss'; 5 | // eslint-disable-next-line import/no-extraneous-dependencies 6 | import list from 'shortcss/lib/list'; 7 | // eslint-disable-next-line import/no-extraneous-dependencies 8 | import cssValues from 'css-values'; 9 | 10 | import { 11 | validProperties, 12 | validOptions, 13 | expectedTypes, 14 | customExpected, 15 | expected, 16 | getTypes, 17 | getIgnoredVariablesOrFunctions, 18 | getIgnoredKeywords, 19 | getIgnoredValues, 20 | getAutoFixFunc, 21 | failedToFix, 22 | } from './lib/validation'; 23 | import defaults, { 24 | ruleName, 25 | SecondaryOptions, 26 | IgnoreValue, 27 | RegExpString, 28 | } from './defaults'; 29 | import unsafeQuietStylelintDeprecationWarning from './unsafe-quiet-stylelint-deprecation-warning'; 30 | 31 | unsafeQuietStylelintDeprecationWarning(); 32 | 33 | const { utils } = stylelint; 34 | const meta: RuleMeta = { 35 | url: 'https://github.com/AndyOGo/stylelint-declaration-strict-value/blob/master/README.md', 36 | fixable: true, 37 | }; 38 | const messages = utils.ruleMessages(ruleName, { 39 | expected, 40 | customExpected, 41 | failedToFix, 42 | }); 43 | /** 44 | * RegExp to skip non-CSS properties. 45 | * 46 | * @internal 47 | */ 48 | const reSkipProp = /^(?:@|\$|--).+$/; 49 | /** 50 | * RegExp to parse CSS, SCSS and less variables. 51 | * - allowing CSS variables to be multi line 52 | * - Sass namespaces and CSS supported 53 | * 54 | * @internal 55 | * @see https://github.com/sass/sass/blob/master/accepted/module-system.md#member-references 56 | * @see https://drafts.csswg.org/css-syntax-3/#ident-token-diagram 57 | */ 58 | // eslint-disable-next-line no-control-regex 59 | const reVar = 60 | /^-?(?:@.+|(?:(?:[a-zA-Z_-]|[^\x20-\x7F])+(?:[a-zA-Z0-9_-]|[^\x20-\x7F])*\.)?\$.+|var\(\s*--[\s\S]+\))$/; 61 | /** 62 | * RegExp to parse functions. 63 | * - irgnoring CSS variables `var(--*)` 64 | * - allow multi line arguments 65 | * 66 | * @internal 67 | */ 68 | const reFunc = /^(?!var\(\s*--)[\s\S]+\([\s\S]*\)$/; 69 | /** 70 | * RegExp to parse regular expressions. 71 | * - supporting patterns 72 | * - and optional flags 73 | * 74 | * @internal 75 | */ 76 | const reRegex = /^\/(.*)\/([a-zA-Z]*)$/; 77 | /** 78 | * @internal 79 | */ 80 | const reColorProp = /color/; 81 | type RegExpArray = [string, string?]; 82 | /** 83 | * Checks if string is a Regular Expression. 84 | * 85 | * @internal 86 | * @param value - Any string. 87 | */ 88 | const checkCssValue = (prop: string, value: string) => 89 | (reColorProp.test(prop) && value === 'transparent') || 90 | reVar.test(value) || 91 | reFunc.test(value) || 92 | cssValues(prop, value); 93 | const isRegexString = (value: string): value is RegExpString => 94 | reRegex.test(value); 95 | /** 96 | * Get pattern and flags of a Regular Expression string. 97 | * 98 | * @internal 99 | * @param value - Any string representing a Regular Expression. 100 | * @returns An Array of pattern and flags of a Regular Expression string. 101 | */ 102 | const getRegexString = (value: string): RegExpArray => 103 | value.match(reRegex)!.slice(1) as RegExpArray; 104 | /** 105 | * Convert a Regular Expression string to an RegExp object. 106 | * 107 | * @internal 108 | * @param value - Any string representing a Regular Expression. 109 | * @returns A Regular Expression object. 110 | */ 111 | const stringToRegex = (value: RegExpString) => { 112 | const [pattern, flags] = getRegexString(value); 113 | return new RegExp(pattern, flags); 114 | }; 115 | /** 116 | * Map ignored value config to a Regular expression. 117 | * 118 | * @internal 119 | * @param ignoreValue - A ignored value property. 120 | * @returns A Regular Expression to match ignored values. 121 | */ 122 | const mapIgnoreValue = (ignoreValue: IgnoreValue) => 123 | isRegexString(`${ignoreValue}`) 124 | ? stringToRegex(`${ignoreValue}`) 125 | : new RegExp(`^${ignoreValue}$`); 126 | 127 | /** 128 | * A string or regular expression matching a CSS property name. 129 | */ 130 | type CSSPropertyName = string | RegExpString; 131 | 132 | /** 133 | * Primary options, a CSS property or list of CSS properties to lint. 134 | * - Regular Expression strings are supported 135 | */ 136 | type PrimaryOptions = CSSPropertyName | CSSPropertyName[]; 137 | 138 | type RuleContext = { 139 | fix?: boolean | undefined; 140 | newline?: string | undefined; 141 | }; 142 | 143 | /** 144 | * Stylelint declaration strict value rule function. 145 | * 146 | * @see https://stylelint.io/developer-guide/plugins 147 | * @param properties - Primary options, a CSS property or list of CSS properties to lint. 148 | * @param options- Secondary options, configure edge cases. 149 | * @param context - Only used for autofixing. 150 | * 151 | * @returns Returns a PostCSS Plugin. 152 | */ 153 | type StylelintPlugin

= Rule; 154 | 155 | const ruleFunction: StylelintPlugin = 156 | ( 157 | properties: PrimaryOptions, 158 | options: SecondaryOptions, 159 | context: RuleContext = {} 160 | ) => 161 | (root: Root, result: PostcssResult) => { 162 | // fix #142 163 | // @see https://github.com/stylelint/stylelint/pull/672/files#diff-78f1c80ffb2836008dd194b3b0ca28f9b46e4897b606f0b3d25a29e57a8d3e61R74 164 | // @see https://stylelint.io/user-guide/configure#message 165 | /* eslint-disable @typescript-eslint/no-explicit-any */ 166 | if ( 167 | result && 168 | (result as any).stylelint && 169 | (result as any).stylelint.customMessages && 170 | (result as any).stylelint.customMessages[ruleName] 171 | ) { 172 | // eslint-disable-next-line no-param-reassign 173 | delete (result as any).stylelint.customMessages[ruleName]; 174 | } 175 | /* eslint-enable @typescript-eslint/no-explicit-any */ 176 | 177 | // validate stylelint plugin options 178 | const hasValidOptions = utils.validateOptions( 179 | result, 180 | ruleName, 181 | { 182 | actual: properties, 183 | possible: validProperties, 184 | }, 185 | { 186 | actual: options, 187 | possible: validOptions, 188 | optional: true, 189 | } 190 | ); 191 | 192 | if (!hasValidOptions) return; 193 | 194 | // normalize options 195 | if (!Array.isArray(properties)) { 196 | // eslint-disable-next-line no-param-reassign 197 | properties = [properties]; 198 | } 199 | 200 | const config: SecondaryOptions = { 201 | ...defaults, 202 | ...options, 203 | }; 204 | const { 205 | ignoreVariables, 206 | ignoreFunctions, 207 | ignoreKeywords, 208 | ignoreValues, 209 | message, 210 | disableFix, 211 | autoFixFunc, 212 | expandShorthand, 213 | recurseLonghand, 214 | } = config; 215 | const autoFixFuncNormalized = getAutoFixFunc( 216 | autoFixFunc, 217 | disableFix, 218 | context.fix 219 | ); 220 | /** 221 | * A hash of regular expression to ignore for a CSS properties. 222 | * @internal 223 | */ 224 | interface RegExpMap { 225 | // [key: CSSPropertyName]: RegExp; 226 | [key: string]: RegExp; 227 | } 228 | /** 229 | * A hash of regular expression to ignore for a CSS properties or `null`. 230 | * @internal 231 | */ 232 | type RegExpKeywordMap = null | RegExpMap; 233 | /** 234 | * A hash of regular expression lists to ignore for a CSS property. 235 | * @internal 236 | */ 237 | interface RegExpList { 238 | // [key: CSSPropertyName]: RegExp[]; 239 | [key: string]: RegExp[]; 240 | } 241 | /** 242 | * A hash of regular expression lists to ignore for a CSS property or `null`. 243 | * @internal 244 | */ 245 | type RegExpValuesList = null | RegExpList; 246 | const reKeywords: RegExpKeywordMap = ignoreKeywords ? {} : null; 247 | const reValues: RegExpValuesList = ignoreValues ? {} : null; 248 | let cssLoaderValues: RegExp; 249 | 250 | if (ignoreVariables) { 251 | const cssLoaderValuesNames: string[] = []; 252 | root.walkAtRules('value', (rule: AtRule) => { 253 | const { params } = rule; 254 | const name = params.split(':')[0].trim(); 255 | 256 | cssLoaderValuesNames.push(name); 257 | }); 258 | 259 | cssLoaderValues = new RegExp(`^-?(:?${cssLoaderValuesNames.join('|')})$`); 260 | } 261 | 262 | // loop through all properties 263 | properties.forEach((property) => { 264 | let propFilter: string | RegExp = property; 265 | 266 | // parse RegExp 267 | if (isRegexString(propFilter)) { 268 | propFilter = stringToRegex(propFilter); 269 | } 270 | 271 | // walk through all declarations filtered by configured properties 272 | root.walkDecls(filterDecl); 273 | 274 | /** 275 | * Filter declarations for matching properties and expand shorthand properties. 276 | * 277 | * @internal 278 | * @param node - A Declaration-Node from PostCSS AST-Parser. 279 | */ 280 | function filterDecl(node: Declaration) { 281 | const { value, prop } = node; 282 | 283 | // skip variable declarations 284 | if (reSkipProp.test(prop)) return; 285 | 286 | const isShortHand = expandShorthand && shortCSS.isShorthand(prop); 287 | 288 | if ( 289 | prop === propFilter || 290 | (!isShortHand && 291 | propFilter instanceof RegExp && 292 | propFilter.test(prop)) 293 | ) { 294 | const values: string[] = list.space(value); 295 | 296 | // handle multi-value props, like scrollbar-color 297 | if (values.length > 1) { 298 | let failedFlag = false; 299 | 300 | values.forEach((valueItem) => { 301 | if (!failedFlag) { 302 | failedFlag = lintDeclStrictValue(node, prop, valueItem); 303 | } 304 | }); 305 | } else { 306 | lintDeclStrictValue(node); 307 | } 308 | } else if (isShortHand) { 309 | const expandedProps = shortCSS.expand(prop, value, recurseLonghand); 310 | let failedFlag = false; 311 | 312 | Object.keys(expandedProps).forEach((longhandProp) => { 313 | const longhandValue = expandedProps[longhandProp]; 314 | 315 | if ( 316 | !failedFlag && 317 | (longhandProp === propFilter || 318 | (propFilter instanceof RegExp && propFilter.test(longhandProp))) 319 | ) { 320 | failedFlag = lintDeclStrictValue( 321 | node, 322 | longhandProp, 323 | longhandValue, 324 | true 325 | ); 326 | } 327 | }); 328 | } 329 | } 330 | 331 | /** 332 | * Lint usages of declarations values against, variables, functions 333 | * or custom keywords - as configured. 334 | * 335 | * @internal 336 | * @param node - A Declaration-Node from PostCSS AST-Parser. 337 | * @param longhandProp - A Declaration-Node from PostCSS AST-Parser. 338 | * @param longhandValue - A Declaration-Node from PostCSS AST-Parser. 339 | * @param isExpanded - Whether or not this declaration was expanded. 340 | * @returns Returns `true` if invalid declaration found, else `false`. 341 | */ 342 | function lintDeclStrictValue( 343 | node: Declaration, 344 | longhandProp?: string, 345 | longhandValue?: string, 346 | isExpanded = false 347 | ) { 348 | const { value: nodeValue, prop: nodeProp } = node; 349 | const value = longhandValue || nodeValue; 350 | 351 | // falsify everything by default 352 | let validVar = false; 353 | let validFunc = false; 354 | let validKeyword = false; 355 | let validValue = false; 356 | 357 | // test variable 358 | if (ignoreVariables) { 359 | // @TODO: deviant regexes to primary options need to be evaluated 360 | const ignoreVariable = getIgnoredVariablesOrFunctions( 361 | ignoreVariables, 362 | property 363 | ); 364 | 365 | if (ignoreVariable) { 366 | validVar = reVar.test(value) || cssLoaderValues.test(value); 367 | } 368 | } 369 | 370 | // test function 371 | if (ignoreFunctions && !validVar) { 372 | // @TODO: deviant regexes to primary options need to be evaluated 373 | const ignoreFunction = getIgnoredVariablesOrFunctions( 374 | ignoreFunctions, 375 | property 376 | ); 377 | 378 | if (ignoreFunction) { 379 | validFunc = reFunc.test(value); 380 | } 381 | } 382 | 383 | // test expanded shorthands are valid 384 | if ( 385 | isExpanded && 386 | (!ignoreVariables || (ignoreVariables && !validVar)) && 387 | (!ignoreFunctions || (ignoreFunctions && !validFunc)) && 388 | checkCssValue(longhandProp!, longhandValue!) !== true 389 | ) { 390 | return false; 391 | } 392 | 393 | // test keywords 394 | if (ignoreKeywords && (!validVar || !validFunc)) { 395 | let reKeyword = reKeywords![property]; 396 | 397 | if (!reKeyword) { 398 | const ignoreKeyword = getIgnoredKeywords(ignoreKeywords, property); 399 | 400 | if (ignoreKeyword) { 401 | reKeyword = new RegExp(`^${ignoreKeyword.join('$|^')}$`); 402 | reKeywords![property] = reKeyword; 403 | } 404 | } 405 | 406 | if (reKeyword) { 407 | validKeyword = reKeyword.test(value); 408 | } 409 | } 410 | 411 | if (ignoreValues && (!validVar || !validFunc || !validKeyword)) { 412 | let reValueList = reValues![property]; 413 | 414 | if (!reValueList) { 415 | const ignoreValue = getIgnoredValues(ignoreValues, property); 416 | 417 | if (ignoreValue) { 418 | reValueList = ignoreValue.map(mapIgnoreValue); 419 | reValues![property] = reValueList; 420 | } 421 | } 422 | 423 | if (reValueList) { 424 | validValue = 425 | reValueList.filter((reValue) => reValue.test(value)).length > 0; 426 | } 427 | } 428 | 429 | // report only if all failed 430 | if (!validVar && !validFunc && !validKeyword && !validValue) { 431 | const types = getTypes(config, property); 432 | 433 | // support auto fixing 434 | if (context.fix && !disableFix && autoFixFuncNormalized) { 435 | try { 436 | const fixedValue = autoFixFuncNormalized( 437 | node, 438 | { 439 | validVar, 440 | validFunc, 441 | validKeyword, 442 | validValue, 443 | longhandProp, 444 | longhandValue, 445 | }, 446 | root, 447 | config 448 | ); 449 | 450 | // apply fixed value if returned 451 | if (fixedValue) { 452 | // eslint-disable-next-line no-param-reassign 453 | node.value = fixedValue; 454 | } 455 | } catch (error) { 456 | const { raws } = node; 457 | // eslint-disable-next-line prefer-destructuring 458 | const start = node.source!.start; 459 | 460 | utils.report({ 461 | ruleName, 462 | result, 463 | node, 464 | line: start!.line, 465 | column: start!.column + nodeProp.length + raws.between!.length, 466 | message: messages.failedToFix(error, value, nodeProp), 467 | } as any); 468 | } 469 | } else { 470 | const { raws } = node; 471 | // eslint-disable-next-line prefer-destructuring 472 | const start = node.source!.start; 473 | 474 | utils.report({ 475 | ruleName, 476 | result, 477 | node, 478 | line: start!.line, 479 | column: start!.column + nodeProp.length + raws.between!.length, 480 | message: message 481 | ? messages.customExpected( 482 | expectedTypes(types), 483 | value, 484 | nodeProp, 485 | message 486 | ) 487 | : messages.expected(expectedTypes(types), value, nodeProp), 488 | } as any); 489 | } 490 | 491 | return true; 492 | } 493 | 494 | return false; 495 | } 496 | }); 497 | }; 498 | 499 | ruleFunction.primaryOptionArray = true; 500 | ruleFunction.ruleName = ruleName; 501 | ruleFunction.messages = messages; 502 | ruleFunction.meta = meta; 503 | 504 | const declarationStrictValuePlugin = stylelint.createPlugin( 505 | ruleName, 506 | ruleFunction 507 | ); 508 | 509 | export default declarationStrictValuePlugin; 510 | export { ruleName, messages, meta, ruleFunction as rule }; 511 | -------------------------------------------------------------------------------- /src/lib/validation.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | 3 | import defaults, { 4 | ruleName, 5 | SecondaryOptions, 6 | IgnoreValue, 7 | IgnoreValueList, 8 | IgnoreValueHash, 9 | IgnoreVariableOrFunctionConfig, 10 | IgnoreVariableOrFunctionHash, 11 | IgnoreValueConfig, 12 | AutoFixFunc, 13 | AutoFixFuncConfig, 14 | isIIgnoreValueHash, 15 | } from '../defaults'; 16 | 17 | /** 18 | * Check if type is either `number` or `string`. 19 | * 20 | * @internal 21 | * @param value - Any value. 22 | * 23 | * @returns Returns `true` if `value`'s type is either `number` or `string`, else `false`. 24 | */ 25 | function isNumberOrString(value: unknown): value is IgnoreValue { 26 | const type = typeof value; 27 | 28 | return type === 'string' || type === 'number'; 29 | } 30 | 31 | /** 32 | * Validate primary options of stylelint plugin config. 33 | * 34 | * @internal 35 | * @param actual - The actual config to validate. 36 | * 37 | * @returns Returns `true` if primary options are valid, else `false`. 38 | */ 39 | export function validProperties( 40 | actual: unknown 41 | ): actual is IgnoreValue | IgnoreValueList { 42 | return ( 43 | isNumberOrString(actual) || 44 | (Array.isArray(actual) && actual.every((item) => isNumberOrString(item))) 45 | ); 46 | } 47 | 48 | /** 49 | * Validate optional hash keyword config. 50 | * 51 | * @internal 52 | * @param actual - A keyword config. 53 | * 54 | * @returns Returns `true` if hash keyword config is valid, else `false`. 55 | */ 56 | function validHash(actual: unknown): actual is IgnoreValueHash { 57 | if (typeof actual !== 'object' || !actual) return false; 58 | 59 | return Object.keys(actual).every((key) => 60 | validProperties((actual as IgnoreValueHash)[key as keyof IgnoreValueHash]) 61 | ); 62 | } 63 | 64 | /** 65 | * Validate optional boolean hash variable/function config. 66 | * 67 | * @internal 68 | * @param actual - A variable/function config. 69 | * 70 | * @returns Returns `true` if hash variable/function config is valid, else `false`. 71 | */ 72 | function validBooleanHash( 73 | actual: unknown 74 | ): actual is IgnoreVariableOrFunctionHash { 75 | if (typeof actual !== 'object' || !actual) return false; 76 | 77 | return Object.keys(actual).every( 78 | (key) => 79 | typeof (actual as IgnoreVariableOrFunctionHash)[ 80 | key as keyof IgnoreVariableOrFunctionHash 81 | ] === 'boolean' 82 | ); 83 | } 84 | 85 | /** 86 | * Validate optional secondary options of stylelint plugin config. 87 | * 88 | * @internal 89 | * @param actual - The actual config to validate. 90 | * 91 | * @returns Returns `true` if secondary options are valid, else `false`. 92 | */ 93 | export function validOptions(actual: SecondaryOptions): boolean { 94 | if (typeof actual !== 'object') return false; 95 | 96 | const allowedKeys = Object.keys(defaults); 97 | if (!Object.keys(actual).every((key) => allowedKeys.indexOf(key) > -1)) 98 | return false; 99 | 100 | if ( 101 | 'ignoreVariables' in actual && 102 | typeof actual.ignoreVariables !== 'boolean' && 103 | !validBooleanHash(actual.ignoreVariables) && 104 | actual.ignoreVariables !== null 105 | ) 106 | return false; 107 | 108 | if ( 109 | 'ignoreFunctions' in actual && 110 | typeof actual.ignoreFunctions !== 'boolean' && 111 | !validBooleanHash(actual.ignoreFunctions) && 112 | actual.ignoreFunctions !== null 113 | ) 114 | return false; 115 | 116 | if ( 117 | 'severity' in actual && 118 | typeof actual.severity !== 'string' && 119 | actual.severity !== null 120 | ) 121 | return false; 122 | 123 | if ( 124 | 'ignoreKeywords' in actual && 125 | !validProperties(actual.ignoreKeywords) && 126 | !validHash(actual.ignoreKeywords) 127 | ) 128 | return false; 129 | 130 | if ( 131 | 'ignoreValues' in actual && 132 | !validProperties(actual.ignoreValues) && 133 | !validHash(actual.ignoreValues) 134 | ) 135 | return false; 136 | 137 | if ( 138 | 'expandShorthand' in actual && 139 | typeof actual.expandShorthand !== 'boolean' && 140 | actual.expandShorthand !== null 141 | ) 142 | return false; 143 | 144 | if ( 145 | 'recurseLonghand' in actual && 146 | typeof actual.recurseLonghand !== 'boolean' && 147 | actual.recurseLonghand !== null 148 | ) 149 | return false; 150 | 151 | if ( 152 | 'message' in actual && 153 | typeof actual.message !== 'string' && 154 | actual.message !== null 155 | ) 156 | return false; 157 | 158 | if ( 159 | 'disableFix' in actual && 160 | typeof actual.disableFix !== 'boolean' && 161 | actual.disableFix !== null 162 | ) 163 | return false; 164 | 165 | if ( 166 | 'autoFixFunc' in actual && 167 | typeof actual.autoFixFunc !== 'function' && 168 | typeof actual.autoFixFunc !== 'string' && 169 | actual.autoFixFunc !== null 170 | ) 171 | return false; 172 | 173 | return true; 174 | } 175 | 176 | /** 177 | * Expected type of CSS value, available by configuration. 178 | * @internal 179 | */ 180 | type ExpectedType = 'variable' | 'function' | 'keyword'; 181 | /** 182 | * Expected types of CSS value, as configured. 183 | * @internal 184 | */ 185 | type ExpectedTypes = Array; 186 | 187 | /** 188 | * Build expected message for stylelint report. 189 | * 190 | * @internal 191 | * @param types - Either `variable`, `function` and/or `keyword`. 192 | * 193 | * @returns Returns an expected types message for stylelint report. 194 | */ 195 | export function expectedTypes(types: ExpectedType | ExpectedTypes): string { 196 | let typesMessage: string; 197 | 198 | if (Array.isArray(types)) { 199 | const typesLast = types.pop(); 200 | 201 | // eslint-disable-next-line no-param-reassign 202 | typesMessage = types.length 203 | ? `${types.join(', ')} or ${typesLast}` 204 | : (typesLast as string); 205 | } else { 206 | typesMessage = types; 207 | } 208 | 209 | return typesMessage; 210 | } 211 | 212 | /** 213 | * Build expected message for stylelint report. 214 | * 215 | * @internal 216 | * @param typesMessage - An expected types message for stylelint report. 217 | * @param value - The CSS declaration's value. 218 | * @param property - The CSS declaration's property. 219 | * 220 | * @returns Returns an expected message for stylelint report. 221 | */ 222 | export function expected( 223 | typesMessage: string, 224 | value: string, 225 | property: string 226 | ): string { 227 | return `Expected ${typesMessage} for "${value}" of "${property}"`; 228 | } 229 | 230 | /** 231 | * Build custom expected message for stylelint report. 232 | * 233 | * @internal 234 | * @param typesMessage - An expected types message for stylelint report. 235 | * @param value - The CSS declaration's value. 236 | * @param property - The CSS declaration's property. 237 | * @param customMessage - A custom message to be delivered upon error interpolated with `${types}`, `${value}` and `${property}`. 238 | * 239 | * @returns Returns a custom expected message for stylelint report. 240 | */ 241 | export function customExpected( 242 | typesMessage: string, 243 | value: string, 244 | property: string, 245 | customMessage: string 246 | ): string { 247 | /* eslint-disable no-template-curly-in-string */ 248 | return customMessage 249 | .replace('${types}', typesMessage) 250 | .replace('${value}', value) 251 | .replace('${property}', property); 252 | /* eslint-enable no-template-curly-in-string */ 253 | } 254 | 255 | /** 256 | * Build failed-to-fix message for stylelint report. 257 | * 258 | * @internal 259 | * @param error - An expression to `throw`. 260 | * @param value - The CSS declaration's value. 261 | * @param property - The CSS declaration's property. 262 | * 263 | * @returns Returns an failed-to-fix message for stylelint report. 264 | */ 265 | export function failedToFix( 266 | error: unknown, 267 | value: string, 268 | property: string 269 | ): string { 270 | if (error && (typeof error === 'string' || error instanceof Error)) { 271 | return typeof error === 'string' ? error : error.message; 272 | } 273 | 274 | return `Property "${property}" with value "${value}" can't be autofixed`; 275 | } 276 | 277 | /** 278 | * Get configured types for stylelint report message. 279 | * 280 | * @internal 281 | * @param config - The secondary stylelint-plugin config. 282 | * @param property - The specific CSS declaration's property of the current iteration. 283 | * 284 | * @returns Returns a list of configured types. 285 | */ 286 | export function getTypes( 287 | config: SecondaryOptions, 288 | property: string 289 | ): ExpectedTypes { 290 | const { ignoreVariables, ignoreFunctions, ignoreKeywords, ignoreValues } = 291 | config; 292 | const types: ExpectedTypes = []; 293 | 294 | if (ignoreVariables) { 295 | types.push('variable'); 296 | } 297 | 298 | if (ignoreFunctions) { 299 | types.push('function'); 300 | } 301 | 302 | if (ignoreKeywords && getIgnoredKeywords(ignoreKeywords, property)) { 303 | types.push('keyword'); 304 | } 305 | 306 | if ( 307 | types.indexOf('keyword') === -1 && 308 | ignoreValues && 309 | getIgnoredValues(ignoreValues, property) 310 | ) { 311 | types.push('keyword'); 312 | } 313 | 314 | return types; 315 | } 316 | 317 | /** 318 | * Get the correct ignored variable or function for a specific CSS declaration's property 319 | * out of a complex `ignoreVariablesOrFunctions` config hash or boolean. 320 | * 321 | * @internal 322 | * @param ignoreVariablesOrFunctions - The variables or functions to ignore. 323 | * @param property - The specific CSS declaration's property of the current iteration. 324 | * 325 | * @returns Returns ignored variable or function for a specific CSS property. 326 | */ 327 | export function getIgnoredVariablesOrFunctions( 328 | ignoreVariablesOrFunctions: IgnoreVariableOrFunctionConfig, 329 | property: string 330 | ): boolean { 331 | // @see: https://github.com/microsoft/TypeScript/issues/41627 332 | // const type = typeof ignoreVariablesOrFunctions 333 | 334 | if (typeof ignoreVariablesOrFunctions === 'boolean') { 335 | return ignoreVariablesOrFunctions; 336 | } 337 | 338 | if ( 339 | typeof ignoreVariablesOrFunctions === 'object' && 340 | ignoreVariablesOrFunctions && 341 | {}.hasOwnProperty.call(ignoreVariablesOrFunctions, property) 342 | ) { 343 | return ignoreVariablesOrFunctions[property]; 344 | } 345 | 346 | return !!ignoreVariablesOrFunctions; 347 | } 348 | 349 | /** 350 | * Get the correct ignored keywords for a specific CSS declaration's property 351 | * out of a complex `ignoreKeywords` config hash or array. 352 | * 353 | * @internal 354 | * @param ignoreKeywords - The keyword/-s to ignore. 355 | * @param property - The specific CSS declaration's property of the current iteration. 356 | * 357 | * @returns Returns ignored keywords for a specific CSS property, or `null`. 358 | */ 359 | export function getIgnoredKeywords( 360 | ignoreKeywords: IgnoreValueConfig, 361 | property: string 362 | ): null | IgnoreValueList { 363 | if (!ignoreKeywords) return null; 364 | 365 | let keywords = ignoreKeywords; 366 | 367 | if (isIIgnoreValueHash(keywords, property)) { 368 | keywords = keywords[property]; 369 | } else if (isIIgnoreValueHash(keywords, '')) { 370 | keywords = keywords['']; 371 | } 372 | 373 | return Array.isArray(keywords) ? keywords : [keywords]; 374 | } 375 | 376 | /** 377 | * Get the correct ignored values for a specific CSS declaration's property 378 | * out of a complex `ignoreValues` config hash or array. 379 | * 380 | * @internal 381 | * @param ignoreValues - The values/-s to ignore. 382 | * @param property - The specific CSS declaration's property of the current iteration. 383 | * @returns Returns ignored values for a specific CSS property, or `null`. 384 | */ 385 | export function getIgnoredValues( 386 | ignoreValues: IgnoreValueConfig, 387 | property: string 388 | ): null | IgnoreValueList { 389 | if (!ignoreValues) return null; 390 | 391 | let values = ignoreValues; 392 | 393 | if (isIIgnoreValueHash(values, property)) { 394 | values = values[property]; 395 | } else if (isIIgnoreValueHash(values, '')) { 396 | values = values['']; 397 | } 398 | 399 | return Array.isArray(values) ? values : [values]; 400 | } 401 | 402 | /** 403 | * Get the auto-fix function either by a function directly or from a source file. 404 | * 405 | * @internal 406 | * @param autoFixFunc - A JavaScript function or a module path to resolve it, also from `cwd`. 407 | * 408 | * @returns Returns the auto-fix function if found, else `null`. 409 | */ 410 | export function getAutoFixFunc( 411 | autoFixFunc: AutoFixFuncConfig, 412 | disableFix?: boolean, 413 | contextFix?: boolean 414 | ): null | AutoFixFunc { 415 | // @see: https://github.com/microsoft/TypeScript/issues/41627 416 | // const type = typeof autoFixFunc 417 | 418 | if (typeof autoFixFunc === 'function') { 419 | return autoFixFunc; 420 | } 421 | 422 | if (typeof autoFixFunc === 'string') { 423 | let resolveAutoFixfunc; 424 | 425 | try { 426 | resolveAutoFixfunc = require.resolve(autoFixFunc); 427 | } catch (error) { 428 | resolveAutoFixfunc = require.resolve( 429 | path.join(process.cwd(), autoFixFunc) 430 | ); 431 | } 432 | 433 | // eslint-disable-next-line import/no-dynamic-require, global-require 434 | return require(resolveAutoFixfunc); 435 | } 436 | 437 | if (!disableFix && contextFix) { 438 | // eslint-disable-next-line no-console 439 | console.warn( 440 | `No \`autoFix\` function provided, consider using \`disableFix\` for "${ruleName}"` 441 | ); 442 | } 443 | 444 | return null; 445 | } 446 | -------------------------------------------------------------------------------- /src/unsafe-quiet-stylelint-deprecation-warning.ts: -------------------------------------------------------------------------------- 1 | import process from 'node:process'; 2 | import { ruleName } from './defaults'; 3 | 4 | // internal warning code 5 | // @see: https://github.com/stylelint/stylelint/blob/3a903800248fcccd4968e8e0dc4a76a4d8b88ff4/lib/utils/emitDeprecationWarning.mjs#L3-L11 6 | const STYLELINT_DEPRECATION_WARNING_PREFIX = 'stylelint:'; 7 | 8 | type Warning = Error & { 9 | code: string; 10 | }; 11 | 12 | /** 13 | * Quiet all stylelint related deprecation warnings like `context.fix` or `utils.report` API. 14 | */ 15 | export default function unsafeQuietStylelintDeprecationWarning(): void { 16 | const original = process.emitWarning; 17 | process.emitWarning = function emitWarning(...args) { 18 | const [message, options] = args; 19 | 20 | if ( 21 | options && 22 | typeof options === 'object' && 23 | options?.type === 'DeprecationWarning' && 24 | options?.code?.startsWith(STYLELINT_DEPRECATION_WARNING_PREFIX) && 25 | ((message && 26 | typeof message === 'string' && 27 | message?.includes(ruleName)) || 28 | options?.detail?.includes(ruleName)) 29 | ) { 30 | return; 31 | } 32 | 33 | original.apply(process, args); 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /test/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["jest"], 3 | "env": { 4 | "jest/globals": true 5 | }, 6 | "globals": { 7 | "testRule": "readonly", 8 | "testCustomAutoFixMessage": "readonly" 9 | }, 10 | "rules": { 11 | "import/no-extraneous-dependencies": ["error", { 12 | "devDependencies": true, 13 | "optionalDependencies": false, 14 | "peerDependencies": false 15 | }], 16 | "jsdoc/require-jsdoc": "off" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/auto-fix-func.js: -------------------------------------------------------------------------------- 1 | import { ruleName } from '../src'; 2 | import autoFixFunc from './helpers/auto-fix-func'; 3 | import autoFixFuncWithThrow from './helpers/auto-fix-func-with-throw'; 4 | 5 | // works if autofix is omitted 6 | testRule({ 7 | ruleName, 8 | 9 | config: ['color'], 10 | 11 | reject: [ 12 | { 13 | code: '.foo { color: #fff; }', 14 | message: `Expected variable or function for "#fff" of "color" (${ruleName})`, 15 | line: 1, 16 | column: 8, 17 | }, 18 | { 19 | code: '.foo { color: red; }', 20 | message: `Expected variable or function for "red" of "color" (${ruleName})`, 21 | line: 1, 22 | column: 8, 23 | }, 24 | ], 25 | }); 26 | 27 | // autofix by function property 28 | testRule({ 29 | ruleName, 30 | fix: true, 31 | 32 | config: [ 33 | ['color', 'font-size', 'display'], 34 | { 35 | autoFixFunc: autoFixFuncWithThrow, 36 | }, 37 | ], 38 | 39 | reject: [ 40 | { 41 | code: '.foo { color: #fff; }', 42 | fixed: '.foo { color: $color-white; }', 43 | message: `Expected variable or function for "#fff" of "color" (scale-unlimited/declaration-strict-value)`, 44 | }, 45 | { 46 | code: '.foo { color: red; }', 47 | fixed: '.foo { color: $color-red; }', 48 | message: `Expected variable or function for "red" of "color" (scale-unlimited/declaration-strict-value)`, 49 | }, 50 | { 51 | code: '.foo { font-size: 16px; }', 52 | unfixable: true, 53 | message: `Expected variable or function for "16px" of "font-size" (${ruleName})`, 54 | line: 1, 55 | column: 8, 56 | }, 57 | { 58 | code: '.foo { color: blue; }', 59 | unfixable: true, 60 | message: `Expected variable or function for "blue" of "color" (scale-unlimited/declaration-strict-value)`, 61 | line: 1, 62 | column: 8, 63 | }, 64 | { 65 | code: '.foo { display: block; }', 66 | unfixable: true, 67 | message: `Expected variable or function for "block" of "display" (scale-unlimited/declaration-strict-value)`, 68 | line: 1, 69 | column: 8, 70 | }, 71 | ], 72 | }); 73 | 74 | testCustomAutoFixMessage({ 75 | ruleName, 76 | fix: true, 77 | 78 | config: [ 79 | ['color', 'font-size', 'display'], 80 | { 81 | autoFixFunc: autoFixFuncWithThrow, 82 | }, 83 | ], 84 | 85 | reject: [ 86 | { 87 | code: '.foo { font-size: 16px; }', 88 | message: `"font-size" is not a color property (${ruleName})`, 89 | }, 90 | { 91 | code: '.foo { color: blue; }', 92 | message: `Can't fix color "blue" (${ruleName})`, 93 | }, 94 | { 95 | code: '.foo { display: block; }', 96 | message: `Property "display" with value "block" can't be autofixed (${ruleName})`, 97 | }, 98 | ], 99 | }); 100 | 101 | // autofix by function property disabled 102 | testRule({ 103 | ruleName, 104 | fix: true, 105 | 106 | config: [ 107 | 'color', 108 | { 109 | autoFixFunc, 110 | disableFix: true, 111 | }, 112 | ], 113 | 114 | reject: [ 115 | { 116 | code: '.foo { color: #fff; }', 117 | unfixable: true, 118 | message: `Expected variable or function for "#fff" of "color" (${ruleName})`, 119 | line: 1, 120 | column: 8, 121 | }, 122 | { 123 | code: '.foo { color: red; }', 124 | unfixable: true, 125 | message: `Expected variable or function for "red" of "color" (${ruleName})`, 126 | line: 1, 127 | column: 8, 128 | }, 129 | ], 130 | }); 131 | 132 | // autofix by file exporting function 133 | testRule({ 134 | ruleName, 135 | fix: true, 136 | 137 | config: [ 138 | 'color', 139 | { 140 | autoFixFunc: './test/helpers/auto-fix-func.js', 141 | }, 142 | ], 143 | 144 | reject: [ 145 | { 146 | code: '.foo { color: #fff; }', 147 | fixed: '.foo { color: $color-white; }', 148 | message: `Expected variable or function for "#fff" of "color" (${ruleName})`, 149 | }, 150 | { 151 | code: '.foo { color: red; }', 152 | fixed: '.foo { color: $color-red; }', 153 | message: `Expected variable or function for "red" of "color" (${ruleName})`, 154 | }, 155 | ], 156 | }); 157 | 158 | // autofix by file exporting function disabled 159 | testRule({ 160 | ruleName, 161 | fix: true, 162 | 163 | config: [ 164 | 'color', 165 | { 166 | autoFixFunc: './test/helpers/auto-fix-func.js', 167 | disableFix: true, 168 | }, 169 | ], 170 | 171 | reject: [ 172 | { 173 | code: '.foo { color: #fff; }', 174 | unfixable: true, 175 | message: `Expected variable or function for "#fff" of "color" (${ruleName})`, 176 | line: 1, 177 | column: 8, 178 | }, 179 | { 180 | code: '.foo { color: red; }', 181 | unfixable: true, 182 | message: `Expected variable or function for "red" of "color" (${ruleName})`, 183 | line: 1, 184 | column: 8, 185 | }, 186 | ], 187 | }); 188 | 189 | testRule({ 190 | ruleName, 191 | 192 | config: [ 193 | 'color', 194 | { 195 | autoFixFunc: true, 196 | }, 197 | ], 198 | 199 | reject: [ 200 | { 201 | code: '.foo { color: red; }', 202 | message: `Invalid option "{"autoFixFunc":true}" for rule "${ruleName}"`, 203 | }, 204 | ], 205 | }); 206 | 207 | testRule({ 208 | ruleName, 209 | 210 | config: [ 211 | 'color', 212 | { 213 | disableFix: 1234, 214 | }, 215 | ], 216 | 217 | reject: [ 218 | { 219 | code: '.foo { color: red; }', 220 | message: `Invalid option "{"disableFix":1234}" for rule "${ruleName}"`, 221 | }, 222 | ], 223 | }); 224 | -------------------------------------------------------------------------------- /test/custom-message.js: -------------------------------------------------------------------------------- 1 | import { ruleName } from '../src'; 2 | 3 | // custom message 4 | testRule({ 5 | ruleName, 6 | 7 | config: [ 8 | 'color', 9 | { 10 | // eslint-disable-next-line no-template-curly-in-string 11 | message: 'Custom expected ${types} for "${value}" of "${property}"', 12 | }, 13 | ], 14 | 15 | reject: [ 16 | { 17 | code: '.foo { color: #fff; }', 18 | message: `Custom expected variable or function for "#fff" of "color" (${ruleName})`, 19 | line: 1, 20 | column: 8, 21 | }, 22 | { 23 | code: '.foo { color: red; }', 24 | message: `Custom expected variable or function for "red" of "color" (${ruleName})`, 25 | line: 1, 26 | column: 8, 27 | }, 28 | ], 29 | }); 30 | 31 | testRule({ 32 | ruleName, 33 | 34 | config: [ 35 | ['/color$/', 'fill', 'stroke'], 36 | { 37 | ignoreVariables: false, 38 | // eslint-disable-next-line no-template-curly-in-string 39 | message: 'Custom expected ${types} for "${value}" of "${property}"', 40 | }, 41 | ], 42 | 43 | reject: [ 44 | { 45 | code: '.foo { color: $red; }', 46 | message: `Custom expected function for "$red" of "color" (${ruleName})`, 47 | line: 1, 48 | column: 8, 49 | }, 50 | ], 51 | }); 52 | 53 | testRule({ 54 | ruleName, 55 | 56 | config: [ 57 | 'color', 58 | { 59 | message: 1234, 60 | }, 61 | ], 62 | 63 | reject: [ 64 | { 65 | code: '.foo { color: red; }', 66 | message: `Invalid option "{"message":1234}" for rule "${ruleName}"`, 67 | }, 68 | ], 69 | }); 70 | -------------------------------------------------------------------------------- /test/default.js: -------------------------------------------------------------------------------- 1 | import { ruleName } from '../src'; 2 | 3 | // default config 4 | testRule({ 5 | ruleName, 6 | 7 | config: [['color', 'content', 'margin']], 8 | 9 | accept: [ 10 | { code: '.foo { color: $bar; }' }, 11 | { code: '.foo { color: namespace.$bar; }' }, 12 | { code: '.foo { color: @bar; }' }, 13 | { code: '.foo { color: var(--bar); }' }, 14 | { code: '.foo { color: var(--bar, fallback); }' }, 15 | { code: '.foo { color: var(--bar, fallback, fallback2); }' }, 16 | { 17 | code: `.foo { color: var( 18 | --bar, 19 | fallback 20 | ); }`, 21 | }, 22 | { 23 | code: `.foo { color: var( 24 | --bar, 25 | fallback, 26 | fallback2 27 | ); }`, 28 | }, 29 | { 30 | code: `@value bar: #000; 31 | .foo { color: bar; }`, 32 | }, 33 | { code: '.foo { color: -$bar; }' }, 34 | { code: '.foo { color: -namespace.$bar; }' }, 35 | { code: '.foo { color: -@bar; }' }, 36 | { code: '.foo { color: -var(--bar); }' }, 37 | { 38 | code: `@value bar: #000; 39 | .foo { color: -bar; }`, 40 | }, 41 | { code: '.foo { color: spacing(); }' }, 42 | { code: '.foo { color: map-get($bar, baz); }' }, 43 | { code: '.foo { color: map-get(namespace.$bar, baz); }' }, 44 | { code: '.foo { color: darken(#fff, 10%); }' }, 45 | { code: '.foo { color: color(#fff, lighten(10%)); }' }, 46 | { 47 | code: `.foo { color: map-get( 48 | $bar, 49 | baz) 50 | ; }`, 51 | }, 52 | { 53 | code: `.foo { color: map-get( 54 | namespace.$bar, 55 | baz) 56 | ; }`, 57 | }, 58 | { 59 | code: `.foo { color: darken( 60 | #fff, 61 | 10%) 62 | ; }`, 63 | }, 64 | { 65 | code: `.foo { color: color( 66 | #fff, 67 | lighten(10%)) 68 | ; }`, 69 | }, 70 | { 71 | code: `.foo { margin: calc( 72 | var(--x) * 73 | var(--y) 74 | ); }`, 75 | }, 76 | ], 77 | 78 | reject: [ 79 | { 80 | code: '.foo { color: #fff; }', 81 | message: `Expected variable or function for "#fff" of "color" (${ruleName})`, 82 | line: 1, 83 | column: 8, 84 | }, 85 | { 86 | code: '.foo { color: red; }', 87 | message: `Expected variable or function for "red" of "color" (${ruleName})`, 88 | line: 1, 89 | column: 8, 90 | }, 91 | { 92 | code: '.foo { color: bar; }', 93 | message: `Expected variable or function for "bar" of "color" (${ruleName})`, 94 | line: 1, 95 | column: 8, 96 | }, 97 | { 98 | code: '.foo { content: "$bar"; }', 99 | message: `Expected variable or function for ""$bar"" of "content" (${ruleName})`, 100 | line: 1, 101 | column: 8, 102 | }, 103 | { 104 | code: '.foo { content: "namespace.$bar"; }', 105 | message: `Expected variable or function for ""namespace.$bar"" of "content" (${ruleName})`, 106 | line: 1, 107 | column: 8, 108 | }, 109 | { 110 | code: '.foo { content: "@bar"; }', 111 | message: `Expected variable or function for ""@bar"" of "content" (${ruleName})`, 112 | line: 1, 113 | column: 8, 114 | }, 115 | { 116 | code: '.foo { content: "var(--bar)"; }', 117 | message: `Expected variable or function for ""var(--bar)"" of "content" (${ruleName})`, 118 | line: 1, 119 | column: 8, 120 | }, 121 | { 122 | code: '.foo { content: "var(--bar, fallback)"; }', 123 | message: `Expected variable or function for ""var(--bar, fallback)"" of "content" (${ruleName})`, 124 | line: 1, 125 | column: 8, 126 | }, 127 | { 128 | code: '.foo { content: "var(--bar, fallback, fallback2)"; }', 129 | message: `Expected variable or function for ""var(--bar, fallback, fallback2)"" of "content" (${ruleName})`, 130 | line: 1, 131 | column: 8, 132 | }, 133 | { 134 | code: `.foo { content: "var( 135 | --bar, 136 | fallback 137 | )"; }`, 138 | message: `Expected variable or function for ""var( 139 | --bar, 140 | fallback 141 | )"" of "content" (${ruleName})`, 142 | line: 1, 143 | column: 8, 144 | }, 145 | { 146 | code: `.foo { content: "var( 147 | --bar, 148 | fallback, 149 | fallback2 150 | )"; }`, 151 | message: `Expected variable or function for ""var( 152 | --bar, 153 | fallback, 154 | fallback2 155 | )"" of "content" (${ruleName})`, 156 | line: 1, 157 | column: 8, 158 | }, 159 | { 160 | code: `@value bar: #000; 161 | .foo { content: "bar"; }`, 162 | message: `Expected variable or function for ""bar"" of "content" (${ruleName})`, 163 | line: 2, 164 | column: 20, 165 | }, 166 | { 167 | code: '.foo { content: "-$bar"; }', 168 | message: `Expected variable or function for ""-$bar"" of "content" (${ruleName})`, 169 | line: 1, 170 | column: 8, 171 | }, 172 | { 173 | code: '.foo { content: "-namespace.$bar"; }', 174 | message: `Expected variable or function for ""-namespace.$bar"" of "content" (${ruleName})`, 175 | line: 1, 176 | column: 8, 177 | }, 178 | { 179 | code: '.foo { content: "-@bar"; }', 180 | message: `Expected variable or function for ""-@bar"" of "content" (${ruleName})`, 181 | line: 1, 182 | column: 8, 183 | }, 184 | { 185 | code: '.foo { content: "-var(--bar)"; }', 186 | message: `Expected variable or function for ""-var(--bar)"" of "content" (${ruleName})`, 187 | line: 1, 188 | column: 8, 189 | }, 190 | { 191 | code: '.foo { content: "-var(--bar, fallback)"; }', 192 | message: `Expected variable or function for ""-var(--bar, fallback)"" of "content" (${ruleName})`, 193 | line: 1, 194 | column: 8, 195 | }, 196 | { 197 | code: '.foo { content: "-var(--bar, fallback, fallback2)"; }', 198 | message: `Expected variable or function for ""-var(--bar, fallback, fallback2)"" of "content" (${ruleName})`, 199 | line: 1, 200 | column: 8, 201 | }, 202 | { 203 | code: `.foo { content: "-var( 204 | --bar, 205 | fallback 206 | )"; }`, 207 | message: `Expected variable or function for ""-var( 208 | --bar, 209 | fallback 210 | )"" of "content" (${ruleName})`, 211 | line: 1, 212 | column: 8, 213 | }, 214 | { 215 | code: `.foo { content: "-var( 216 | --bar, 217 | fallback, 218 | fallback2 219 | )"; }`, 220 | message: `Expected variable or function for ""-var( 221 | --bar, 222 | fallback, 223 | fallback2 224 | )"" of "content" (${ruleName})`, 225 | line: 1, 226 | column: 8, 227 | }, 228 | { 229 | code: '.foo { content: "spacing()"; }', 230 | message: `Expected variable or function for ""spacing()"" of "content" (${ruleName})`, 231 | line: 1, 232 | column: 8, 233 | }, 234 | { 235 | code: '.foo { content: "map-get($bar, baz)"; }', 236 | message: `Expected variable or function for ""map-get($bar, baz)"" of "content" (${ruleName})`, 237 | line: 1, 238 | column: 8, 239 | }, 240 | { 241 | code: '.foo { content: "map-get(namespace.$bar, baz)"; }', 242 | message: `Expected variable or function for ""map-get(namespace.$bar, baz)"" of "content" (${ruleName})`, 243 | line: 1, 244 | column: 8, 245 | }, 246 | { 247 | code: '.foo { content: "darken(#fff, 10%)"; }', 248 | message: `Expected variable or function for ""darken(#fff, 10%)"" of "content" (${ruleName})`, 249 | line: 1, 250 | column: 8, 251 | }, 252 | { 253 | code: '.foo { content: "color(#fff, lighten(10%))"; }', 254 | message: `Expected variable or function for ""color(#fff, lighten(10%))"" of "content" (${ruleName})`, 255 | line: 1, 256 | column: 8, 257 | }, 258 | { 259 | code: `.foo { content: "map-get( 260 | $bar, 261 | baz)" 262 | ; }`, 263 | message: `Expected variable or function for ""map-get( 264 | $bar, 265 | baz)"" of "content" (${ruleName})`, 266 | line: 1, 267 | column: 8, 268 | }, 269 | { 270 | code: `.foo { content: "map-get( 271 | namespace.$bar, 272 | baz)" 273 | ; }`, 274 | message: `Expected variable or function for ""map-get( 275 | namespace.$bar, 276 | baz)"" of "content" (${ruleName})`, 277 | line: 1, 278 | column: 8, 279 | }, 280 | { 281 | code: `.foo { content: "darken( 282 | #fff, 283 | 10%)" 284 | ; }`, 285 | message: `Expected variable or function for ""darken( 286 | #fff, 287 | 10%)"" of "content" (${ruleName})`, 288 | line: 1, 289 | column: 8, 290 | }, 291 | { 292 | code: `.foo { content: "color( 293 | #fff, 294 | lighten(10%))" 295 | ; }`, 296 | message: `Expected variable or function for ""color( 297 | #fff, 298 | lighten(10%))"" of "content" (${ruleName})`, 299 | line: 1, 300 | column: 8, 301 | }, 302 | { 303 | code: `.foo { content: "calc( 304 | var(--x) * 305 | var(--y) 306 | )"; }`, 307 | message: `Expected variable or function for ""calc( 308 | var(--x) * 309 | var(--y) 310 | )"" of "content" (${ruleName})`, 311 | line: 1, 312 | column: 8, 313 | }, 314 | ], 315 | }); 316 | -------------------------------------------------------------------------------- /test/helpers/auto-fix-func-with-throw.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line consistent-return, no-unused-vars, @typescript-eslint/no-unused-vars 2 | function autoFixFunc(node, validation, root, config) { 3 | const { value, prop } = node; 4 | 5 | if (prop === 'color') { 6 | // eslint-disable-next-line default-case 7 | switch (value) { 8 | case '#fff': 9 | // auto-fix by returned value 10 | return '$color-white'; 11 | 12 | case 'red': 13 | // auto-fix by PostCSS AST tranformation 14 | // eslint-disable-next-line no-param-reassign 15 | node.value = '$color-red'; 16 | // eslint-disable-next-line consistent-return 17 | return; 18 | 19 | default: 20 | // eslint-disable-next-line @typescript-eslint/no-throw-literal 21 | throw `Can't fix color "${value}"`; 22 | } 23 | } else if (prop === 'font-size') { 24 | throw new Error(`"${prop}" is not a color property`); 25 | } 26 | 27 | // eslint-disable-next-line @typescript-eslint/no-throw-literal 28 | throw null; 29 | } 30 | 31 | module.exports = autoFixFunc; 32 | -------------------------------------------------------------------------------- /test/helpers/auto-fix-func.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line consistent-return, no-unused-vars, @typescript-eslint/no-unused-vars 2 | function autoFixFunc(node, validation, root, config) { 3 | const { value, prop } = node; 4 | 5 | if (prop === 'color') { 6 | // eslint-disable-next-line default-case 7 | switch (value) { 8 | case '#fff': 9 | // auto-fix by returned value 10 | return '$color-white'; 11 | 12 | case 'red': 13 | // auto-fix by PostCSS AST tranformation 14 | // eslint-disable-next-line no-param-reassign 15 | node.value = '$color-red'; 16 | } 17 | } 18 | } 19 | 20 | module.exports = autoFixFunc; 21 | -------------------------------------------------------------------------------- /test/ignore-functions.js: -------------------------------------------------------------------------------- 1 | import { ruleName } from '../src'; 2 | 3 | // disabling ignoreFunction 4 | testRule({ 5 | ruleName, 6 | 7 | config: [ 8 | ['color', 'margin'], 9 | { 10 | ignoreFunctions: false, 11 | }, 12 | ], 13 | 14 | accept: [ 15 | { code: '.foo { color: $bar; }' }, 16 | { code: '.foo { color: namespace.$bar; }' }, 17 | { code: '.foo { color: @bar; }' }, 18 | { code: '.foo { color: var(--bar); }' }, 19 | { code: '.foo { color: var(--bar, fallback); }' }, 20 | { code: '.foo { color: var(--bar, fallback, fallback2); }' }, 21 | { 22 | code: `.foo { color: var( 23 | --bar, 24 | fallback 25 | ); }`, 26 | }, 27 | { 28 | code: `.foo { color: var( 29 | --bar, 30 | fallback, 31 | fallback2 32 | ); }`, 33 | }, 34 | ], 35 | 36 | reject: [ 37 | { 38 | code: '.foo { color: #fff; }', 39 | message: `Expected variable for "#fff" of "color" (${ruleName})`, 40 | line: 1, 41 | column: 8, 42 | }, 43 | { 44 | code: '.foo { color: red; }', 45 | message: `Expected variable for "red" of "color" (${ruleName})`, 46 | line: 1, 47 | column: 8, 48 | }, 49 | { 50 | code: '.foo { color: map-get($bar, baz); }', 51 | message: `Expected variable for "map-get($bar, baz)" of "color" (${ruleName})`, 52 | line: 1, 53 | column: 8, 54 | }, 55 | { 56 | code: '.foo { color: map-get(namespace.$bar, baz); }', 57 | message: `Expected variable for "map-get(namespace.$bar, baz)" of "color" (${ruleName})`, 58 | line: 1, 59 | column: 8, 60 | }, 61 | { 62 | code: '.foo { color: darken(#fff, 10%); }', 63 | message: `Expected variable for "darken(#fff, 10%)" of "color" (${ruleName})`, 64 | line: 1, 65 | column: 8, 66 | }, 67 | { 68 | code: '.foo { color: color(#fff, lighten(10%)); }', 69 | message: `Expected variable for "color(#fff, lighten(10%))" of "color" (${ruleName})`, 70 | line: 1, 71 | column: 8, 72 | }, 73 | { 74 | code: `.foo { color: map-get( 75 | $bar, 76 | baz) 77 | ; }`, 78 | message: `Expected variable for "map-get( 79 | $bar, 80 | baz)" of "color" (${ruleName})`, 81 | line: 1, 82 | column: 8, 83 | }, 84 | { 85 | code: `.foo { color: map-get( 86 | namespace.$bar, 87 | baz) 88 | ; }`, 89 | message: `Expected variable for "map-get( 90 | namespace.$bar, 91 | baz)" of "color" (${ruleName})`, 92 | line: 1, 93 | column: 8, 94 | }, 95 | { 96 | code: `.foo { color: darken( 97 | #fff, 98 | 10%) 99 | ; }`, 100 | message: `Expected variable for "darken( 101 | #fff, 102 | 10%)" of "color" (${ruleName})`, 103 | line: 1, 104 | column: 8, 105 | }, 106 | { 107 | code: `.foo { color: color( 108 | #fff, 109 | lighten(10%)) 110 | ; }`, 111 | message: `Expected variable for "color( 112 | #fff, 113 | lighten(10%))" of "color" (${ruleName})`, 114 | line: 1, 115 | column: 8, 116 | }, 117 | { 118 | code: `.foo { margin: calc( 119 | var(--x) * 120 | var(--y) 121 | ); }`, 122 | message: `Expected variable for "calc( 123 | var(--x) * 124 | var(--y) 125 | )" of "margin" (${ruleName})`, 126 | line: 1, 127 | column: 8, 128 | }, 129 | ], 130 | }); 131 | 132 | testRule({ 133 | ruleName, 134 | 135 | config: [ 136 | ['color', 'margin'], 137 | { 138 | ignoreFunctions: { 139 | margin: false, 140 | }, 141 | }, 142 | ], 143 | 144 | accept: [ 145 | { code: '.foo { color: $bar; }' }, 146 | { code: '.foo { color: namespace.$bar; }' }, 147 | { code: '.foo { color: @bar; }' }, 148 | { code: '.foo { color: var(--bar); }' }, 149 | { code: '.foo { color: var(--bar, fallback); }' }, 150 | { code: '.foo { color: var(--bar, fallback, fallback2); }' }, 151 | { 152 | code: `.foo { color: var( 153 | --bar, 154 | fallback 155 | ); }`, 156 | }, 157 | { 158 | code: `.foo { color: var( 159 | --bar, 160 | fallback, 161 | fallback2 162 | ); }`, 163 | }, 164 | { 165 | code: '.foo { color: map-get($bar, baz); }', 166 | }, 167 | { 168 | code: '.foo { color: map-get(namespace.$bar, baz); }', 169 | }, 170 | { 171 | code: '.foo { color: darken(#fff, 10%); }', 172 | }, 173 | { 174 | code: '.foo { color: color(#fff, lighten(10%)); }', 175 | }, 176 | { 177 | code: `.foo { color: map-get( 178 | $bar, 179 | baz) 180 | ; }`, 181 | }, 182 | { 183 | code: `.foo { color: map-get( 184 | namespace.$bar, 185 | baz) 186 | ; }`, 187 | }, 188 | { 189 | code: `.foo { color: darken( 190 | #fff, 191 | 10%) 192 | ; }`, 193 | }, 194 | { 195 | code: `.foo { color: color( 196 | #fff, 197 | lighten(10%)) 198 | ; }`, 199 | }, 200 | ], 201 | 202 | reject: [ 203 | { 204 | code: '.foo { color: #fff; }', 205 | message: `Expected variable or function for "#fff" of "color" (${ruleName})`, 206 | line: 1, 207 | column: 8, 208 | }, 209 | { 210 | code: '.foo { color: red; }', 211 | message: `Expected variable or function for "red" of "color" (${ruleName})`, 212 | line: 1, 213 | column: 8, 214 | }, 215 | { 216 | code: `.foo { margin: calc( 217 | var(--x) * 218 | var(--y) 219 | ); }`, 220 | message: `Expected variable or function for "calc( 221 | var(--x) * 222 | var(--y) 223 | )" of "margin" (${ruleName})`, 224 | line: 1, 225 | column: 8, 226 | }, 227 | ], 228 | }); 229 | 230 | testRule({ 231 | ruleName, 232 | 233 | config: [ 234 | 'color', 235 | { 236 | ignoreFunctions: 'foo', 237 | }, 238 | ], 239 | 240 | reject: [ 241 | { 242 | code: '.foo { color: red; }', 243 | message: `Invalid option "{"ignoreFunctions":"foo"}" for rule "${ruleName}"`, 244 | }, 245 | ], 246 | }); 247 | -------------------------------------------------------------------------------- /test/ignore-unlisted-properties.js: -------------------------------------------------------------------------------- 1 | import { ruleName } from '../src'; 2 | 3 | // ignore unlisted properties 4 | testRule({ 5 | ruleName, 6 | 7 | config: 'color', 8 | 9 | accept: [ 10 | { code: '.foo { display: block; }' }, 11 | { code: '.foo { position: absolute; }' }, 12 | ], 13 | }); 14 | -------------------------------------------------------------------------------- /test/ignore-variables.js: -------------------------------------------------------------------------------- 1 | import { ruleName } from '../src'; 2 | 3 | // disabling ignoreVariables 4 | testRule({ 5 | ruleName, 6 | 7 | config: [ 8 | ['color', 'margin'], 9 | { 10 | ignoreVariables: false, 11 | }, 12 | ], 13 | 14 | accept: [ 15 | { code: '.foo { color: spacing(); }' }, 16 | { code: '.foo { color: map-get($bar, baz); }' }, 17 | { code: '.foo { color: map-get(namespace.$bar, baz); }' }, 18 | { code: '.foo { color: darken(#fff, 10%); }' }, 19 | { code: '.foo { color: color(#fff, lighten(10%)); }' }, 20 | { 21 | code: `.foo { color: map-get( 22 | $bar, 23 | baz) 24 | ; }`, 25 | }, 26 | { 27 | code: `.foo { color: map-get( 28 | namespace.$bar, 29 | baz) 30 | ; }`, 31 | }, 32 | { 33 | code: `.foo { color: darken( 34 | #fff, 35 | 10%) 36 | ; }`, 37 | }, 38 | { 39 | code: `.foo { color: color( 40 | #fff, 41 | lighten(10%)) 42 | ; }`, 43 | }, 44 | { 45 | code: `.foo { margin: calc( 46 | var(--x) * 47 | var(--y) 48 | ); }`, 49 | }, 50 | ], 51 | 52 | reject: [ 53 | { 54 | code: '.foo { color: #fff; }', 55 | message: `Expected function for "#fff" of "color" (${ruleName})`, 56 | line: 1, 57 | column: 8, 58 | }, 59 | { 60 | code: '.foo { color: red; }', 61 | message: `Expected function for "red" of "color" (${ruleName})`, 62 | line: 1, 63 | column: 8, 64 | }, 65 | { 66 | code: '.foo { color: $bar; }', 67 | message: `Expected function for "$bar" of "color" (${ruleName})`, 68 | line: 1, 69 | column: 8, 70 | }, 71 | { 72 | code: '.foo { color: namespace.$bar; }', 73 | message: `Expected function for "namespace.$bar" of "color" (${ruleName})`, 74 | line: 1, 75 | column: 8, 76 | }, 77 | { 78 | code: '.foo { color: @bar; }', 79 | message: `Expected function for "@bar" of "color" (${ruleName})`, 80 | line: 1, 81 | column: 8, 82 | }, 83 | { 84 | code: '.foo { color: var(--bar); }', 85 | message: `Expected function for "var(--bar)" of "color" (${ruleName})`, 86 | line: 1, 87 | column: 8, 88 | }, 89 | { 90 | code: `.foo { color: var( 91 | --bar, 92 | fallback 93 | ); }`, 94 | message: `Expected function for "var( 95 | --bar, 96 | fallback 97 | )" of "color" (${ruleName})`, 98 | line: 1, 99 | column: 8, 100 | }, 101 | { 102 | code: `.foo { color: var( 103 | --bar, 104 | fallback, 105 | fallback2 106 | ); }`, 107 | message: `Expected function for "var( 108 | --bar, 109 | fallback, 110 | fallback2 111 | )" of "color" (${ruleName})`, 112 | line: 1, 113 | column: 8, 114 | }, 115 | { 116 | code: `@value bar: #000; 117 | .foo { color: bar; }`, 118 | message: `Expected function for "bar" of "color" (${ruleName})`, 119 | line: 2, 120 | column: 20, 121 | }, 122 | ], 123 | }); 124 | 125 | testRule({ 126 | ruleName, 127 | 128 | config: [ 129 | ['color', 'margin'], 130 | { 131 | ignoreVariables: { 132 | color: false, 133 | }, 134 | }, 135 | ], 136 | 137 | accept: [ 138 | { code: '.foo { color: spacing(); }' }, 139 | { code: '.foo { color: map-get($bar, baz); }' }, 140 | { code: '.foo { color: map-get(namespace.$bar, baz); }' }, 141 | { code: '.foo { color: darken(#fff, 10%); }' }, 142 | { code: '.foo { color: color(#fff, lighten(10%)); }' }, 143 | { 144 | code: `.foo { color: map-get( 145 | $bar, 146 | baz) 147 | ; }`, 148 | }, 149 | { 150 | code: `.foo { color: map-get( 151 | namespace.$bar, 152 | baz) 153 | ; }`, 154 | }, 155 | { 156 | code: `.foo { color: darken( 157 | #fff, 158 | 10%) 159 | ; }`, 160 | }, 161 | { 162 | code: `.foo { color: color( 163 | #fff, 164 | lighten(10%)) 165 | ; }`, 166 | }, 167 | { code: '.foo { margin: namespace.$bar; }' }, 168 | { code: '.foo { margin: @bar; }' }, 169 | { code: '.foo { margin: var(--bar); }' }, 170 | { 171 | code: `.foo { margin: calc( 172 | var(--x) * 173 | var(--y) 174 | ); }`, 175 | }, 176 | ], 177 | 178 | reject: [ 179 | { 180 | code: '.foo { color: #fff; }', 181 | message: `Expected variable or function for "#fff" of "color" (${ruleName})`, 182 | line: 1, 183 | column: 8, 184 | }, 185 | { 186 | code: '.foo { color: red; }', 187 | message: `Expected variable or function for "red" of "color" (${ruleName})`, 188 | line: 1, 189 | column: 8, 190 | }, 191 | { 192 | code: '.foo { color: $bar; }', 193 | message: `Expected variable or function for "$bar" of "color" (${ruleName})`, 194 | line: 1, 195 | column: 8, 196 | }, 197 | { 198 | code: '.foo { color: namespace.$bar; }', 199 | message: `Expected variable or function for "namespace.$bar" of "color" (${ruleName})`, 200 | line: 1, 201 | column: 8, 202 | }, 203 | { 204 | code: '.foo { color: @bar; }', 205 | message: `Expected variable or function for "@bar" of "color" (${ruleName})`, 206 | line: 1, 207 | column: 8, 208 | }, 209 | { 210 | code: '.foo { color: var(--bar); }', 211 | message: `Expected variable or function for "var(--bar)" of "color" (${ruleName})`, 212 | line: 1, 213 | column: 8, 214 | }, 215 | { 216 | code: `.foo { color: var( 217 | --bar, 218 | fallback 219 | ); }`, 220 | message: `Expected variable or function for "var( 221 | --bar, 222 | fallback 223 | )" of "color" (${ruleName})`, 224 | line: 1, 225 | column: 8, 226 | }, 227 | { 228 | code: `.foo { color: var( 229 | --bar, 230 | fallback, 231 | fallback2 232 | ); }`, 233 | message: `Expected variable or function for "var( 234 | --bar, 235 | fallback, 236 | fallback2 237 | )" of "color" (${ruleName})`, 238 | line: 1, 239 | column: 8, 240 | }, 241 | { 242 | code: `@value bar: #000; 243 | .foo { color: bar; }`, 244 | message: `Expected variable or function for "bar" of "color" (${ruleName})`, 245 | line: 2, 246 | column: 20, 247 | }, 248 | ], 249 | }); 250 | 251 | testRule({ 252 | ruleName, 253 | 254 | config: [ 255 | 'color', 256 | { 257 | ignoreVariables: 'foo', 258 | }, 259 | ], 260 | 261 | reject: [ 262 | { 263 | code: '.foo { color: red; }', 264 | message: `Invalid option "{"ignoreVariables":"foo"}" for rule "${ruleName}"`, 265 | }, 266 | ], 267 | }); 268 | -------------------------------------------------------------------------------- /test/keywords-hash.js: -------------------------------------------------------------------------------- 1 | import { ruleName } from '../src'; 2 | 3 | // ignore keywords hash 4 | testRule({ 5 | ruleName, 6 | 7 | config: [ 8 | ['/color$/', 'fill', 'z-index', 'display'], 9 | { 10 | ignoreKeywords: { 11 | '/color$/': ['transparent', 'currentColor'], 12 | fill: 'inherit', 13 | 'z-index': 0, 14 | '': 'initial', 15 | }, 16 | }, 17 | ], 18 | 19 | accept: [ 20 | { code: '.foo { color: transparent; }' }, 21 | { code: '.foo { color: currentColor; }' }, 22 | { code: '.foo { background-color: transparent; }' }, 23 | { code: '.foo { background-color: currentColor; }' }, 24 | { code: '.foo { border-color: transparent; }' }, 25 | { code: '.foo { border-color: currentColor; }' }, 26 | { code: '.foo { fill: inherit; }' }, 27 | { code: '.foo { z-index: 0; }' }, 28 | { code: '.foo { display: initial; }' }, 29 | ], 30 | 31 | reject: [ 32 | { 33 | code: '.foo { color: inherit; }', 34 | message: `Expected variable, function or keyword for "inherit" of "color" (${ruleName})`, 35 | line: 1, 36 | column: 8, 37 | }, 38 | { 39 | code: '.foo { fill: currentColor; }', 40 | message: `Expected variable, function or keyword for "currentColor" of "fill" (${ruleName})`, 41 | line: 1, 42 | column: 8, 43 | }, 44 | { 45 | code: '.foo { z-index: 1; }', 46 | message: `Expected variable, function or keyword for "1" of "z-index" (${ruleName})`, 47 | line: 1, 48 | column: 8, 49 | }, 50 | { 51 | code: '.foo { display: block; }', 52 | message: `Expected variable, function or keyword for "block" of "display" (${ruleName})`, 53 | line: 1, 54 | column: 8, 55 | }, 56 | ], 57 | }); 58 | -------------------------------------------------------------------------------- /test/multiple-keywords.js: -------------------------------------------------------------------------------- 1 | import { ruleName } from '../src'; 2 | 3 | // ignore multiple keywords 4 | testRule({ 5 | ruleName, 6 | 7 | config: [ 8 | 'color', 9 | { 10 | ignoreKeywords: ['transparent', 'currentColor', 'blue'], 11 | }, 12 | ], 13 | 14 | accept: [ 15 | { code: '.foo { color: transparent; }' }, 16 | { code: '.foo { color: currentColor; }' }, 17 | { code: '.foo { color: blue; }' }, 18 | ], 19 | 20 | reject: [ 21 | { 22 | code: '.foo { color: inherit; }', 23 | message: `Expected variable, function or keyword for "inherit" of "color" (${ruleName})`, 24 | line: 1, 25 | column: 8, 26 | }, 27 | ], 28 | }); 29 | -------------------------------------------------------------------------------- /test/multiple-properties.js: -------------------------------------------------------------------------------- 1 | import { ruleName } from '../src'; 2 | 3 | // array of properties 4 | testRule({ 5 | ruleName, 6 | 7 | config: [['color', 'font-size', 'fill']], 8 | 9 | accept: [ 10 | { code: '.foo { color: $bar; }' }, 11 | { code: '.foo { color: namespace.$bar; }' }, 12 | { code: '.foo { color: @bar; }' }, 13 | { code: '.foo { color: var(--bar); }' }, 14 | { code: '.foo { font-size: $bar; }' }, 15 | { code: '.foo { font-size: namespace.$bar; }' }, 16 | { code: '.foo { font-size: @bar; }' }, 17 | { code: '.foo { font-size: var(--bar); }' }, 18 | { code: '.foo { fill: $bar; }' }, 19 | { code: '.foo { fill: namespace.$bar; }' }, 20 | { code: '.foo { fill: @bar; }' }, 21 | { code: '.foo { fill: var(--bar); }' }, 22 | ], 23 | 24 | reject: [ 25 | { 26 | code: '.foo { color: #fff; }', 27 | message: `Expected variable or function for "#fff" of "color" (${ruleName})`, 28 | line: 1, 29 | column: 8, 30 | }, 31 | { 32 | code: '.foo { font-size: 16px; }', 33 | message: `Expected variable or function for "16px" of "font-size" (${ruleName})`, 34 | line: 1, 35 | column: 8, 36 | }, 37 | { 38 | code: '.foo { fill: #fff; }', 39 | message: `Expected variable or function for "#fff" of "fill" (${ruleName})`, 40 | line: 1, 41 | column: 8, 42 | }, 43 | ], 44 | }); 45 | -------------------------------------------------------------------------------- /test/multiple-values.js: -------------------------------------------------------------------------------- 1 | import { ruleName } from '../src'; 2 | 3 | // ignore multiple keywords 4 | testRule({ 5 | ruleName, 6 | 7 | config: [ 8 | 'color', 9 | { 10 | ignoreValues: ['transparent', '/^#[0-9a-fA-F]{3,6}$/', '/^red$/i'], 11 | }, 12 | ], 13 | 14 | accept: [ 15 | { code: '.foo { color: transparent; }' }, 16 | { code: '.foo { color: #fff; }' }, 17 | { code: '.foo { color: #ffffff; }' }, 18 | { code: '.foo { color: red; }' }, 19 | { code: '.foo { color: Red; }' }, 20 | { code: '.foo { color: REd; }' }, 21 | { code: '.foo { color: RED; }' }, 22 | { code: '.foo { color: rED; }' }, 23 | { code: '.foo { color: reD; }' }, 24 | ], 25 | 26 | reject: [ 27 | { 28 | code: '.foo { color: inherit; }', 29 | message: `Expected variable, function or keyword for "inherit" of "color" (${ruleName})`, 30 | line: 1, 31 | column: 8, 32 | }, 33 | ], 34 | }); 35 | -------------------------------------------------------------------------------- /test/regex-property.js: -------------------------------------------------------------------------------- 1 | import { ruleName } from '../src'; 2 | 3 | // RegExp properties 4 | testRule({ 5 | ruleName, 6 | 7 | config: '/color$/', 8 | 9 | accept: [ 10 | { code: '.foo { color: $bar; }' }, 11 | { code: '.foo { color: namespace.$bar; }' }, 12 | { code: '.foo { color: @bar; }' }, 13 | { code: '.foo { color: var(--bar); }' }, 14 | { code: '.foo { background-color: $bar; }' }, 15 | { code: '.foo { background-color: namespace.$bar; }' }, 16 | { code: '.foo { background-color: @bar; }' }, 17 | { code: '.foo { background-color: var(--bar); }' }, 18 | { code: '.foo { border-color: $bar; }' }, 19 | { code: '.foo { border-color: namespace.$bar; }' }, 20 | { code: '.foo { border-color: @bar; }' }, 21 | { code: '.foo { border-color: var(--bar); }' }, 22 | ], 23 | 24 | reject: [ 25 | { 26 | code: '.foo { color: #fff; }', 27 | message: `Expected variable or function for "#fff" of "color" (${ruleName})`, 28 | line: 1, 29 | column: 8, 30 | }, 31 | { 32 | code: '.foo { color: red; }', 33 | message: `Expected variable or function for "red" of "color" (${ruleName})`, 34 | line: 1, 35 | column: 8, 36 | }, 37 | { 38 | code: '.foo { background-color: #fff; }', 39 | message: `Expected variable or function for "#fff" of "background-color" (${ruleName})`, 40 | line: 1, 41 | column: 8, 42 | }, 43 | { 44 | code: '.foo { background-color: red; }', 45 | message: `Expected variable or function for "red" of "background-color" (${ruleName})`, 46 | line: 1, 47 | column: 8, 48 | }, 49 | { 50 | code: '.foo { border-color: #fff; }', 51 | message: `Expected variable or function for "#fff" of "border-color" (${ruleName})`, 52 | line: 1, 53 | column: 8, 54 | }, 55 | { 56 | code: '.foo { border-color: red; }', 57 | message: `Expected variable or function for "red" of "border-color" (${ruleName})`, 58 | line: 1, 59 | column: 8, 60 | }, 61 | ], 62 | }); 63 | 64 | // RegExp properties with i flag 65 | testRule({ 66 | ruleName, 67 | 68 | config: '/color$/i', 69 | 70 | accept: [ 71 | { code: '.foo { color: $bar; }' }, 72 | { code: '.foo { color: namespace.$bar; }' }, 73 | { code: '.foo { color: @bar; }' }, 74 | { code: '.foo { color: var(--bar); }' }, 75 | { code: '.foo { background-color: $bar; }' }, 76 | { code: '.foo { background-color: namespace.$bar; }' }, 77 | { code: '.foo { background-color: @bar; }' }, 78 | { code: '.foo { background-color: var(--bar); }' }, 79 | { code: '.foo { border-color: $bar; }' }, 80 | { code: '.foo { border-color: namespace.$bar; }' }, 81 | { code: '.foo { border-color: @bar; }' }, 82 | { code: '.foo { border-color: var(--bar); }' }, 83 | ], 84 | 85 | reject: [ 86 | { 87 | code: '.foo { color: #fff; }', 88 | message: `Expected variable or function for "#fff" of "color" (${ruleName})`, 89 | line: 1, 90 | column: 8, 91 | }, 92 | { 93 | code: '.foo { color: red; }', 94 | message: `Expected variable or function for "red" of "color" (${ruleName})`, 95 | line: 1, 96 | column: 8, 97 | }, 98 | { 99 | code: '.foo { background-color: #fff; }', 100 | message: `Expected variable or function for "#fff" of "background-color" (${ruleName})`, 101 | line: 1, 102 | column: 8, 103 | }, 104 | { 105 | code: '.foo { background-color: red; }', 106 | message: `Expected variable or function for "red" of "background-color" (${ruleName})`, 107 | line: 1, 108 | column: 8, 109 | }, 110 | { 111 | code: '.foo { border-color: #fff; }', 112 | message: `Expected variable or function for "#fff" of "border-color" (${ruleName})`, 113 | line: 1, 114 | column: 8, 115 | }, 116 | { 117 | code: '.foo { border-color: red; }', 118 | message: `Expected variable or function for "red" of "border-color" (${ruleName})`, 119 | line: 1, 120 | column: 8, 121 | }, 122 | ], 123 | }); 124 | -------------------------------------------------------------------------------- /test/severity.js: -------------------------------------------------------------------------------- 1 | import { ruleName } from '../src'; 2 | 3 | // custom message 4 | testRule({ 5 | ruleName, 6 | 7 | config: [ 8 | 'color', 9 | { 10 | severity: 'warning', 11 | }, 12 | ], 13 | 14 | reject: [ 15 | { 16 | code: '.foo { color: #fff; }', 17 | message: `Expected variable or function for "#fff" of "color" (${ruleName})`, 18 | line: 1, 19 | column: 8, 20 | }, 21 | { 22 | code: '.foo { color: red; }', 23 | message: `Expected variable or function for "red" of "color" (${ruleName})`, 24 | line: 1, 25 | column: 8, 26 | }, 27 | ], 28 | }); 29 | 30 | testRule({ 31 | ruleName, 32 | 33 | config: [ 34 | 'color', 35 | { 36 | severity: 1234, 37 | }, 38 | ], 39 | 40 | reject: [ 41 | { 42 | code: '.foo { color: red; }', 43 | message: `Invalid option "{"severity":1234}" for rule "${ruleName}"`, 44 | }, 45 | ], 46 | }); 47 | -------------------------------------------------------------------------------- /test/shorthand.js: -------------------------------------------------------------------------------- 1 | import { ruleName } from '../src'; 2 | 3 | // default config 4 | testRule({ 5 | ruleName, 6 | 7 | config: ['/color/', { expandShorthand: true }], 8 | 9 | accept: [ 10 | { code: '.foo { scrollbar-color: $foo @bar; }' }, 11 | { code: '.foo { scrollbar-color: namespace.$bar var(--bar); }' }, 12 | { code: '.foo { border-color: $color; }' }, 13 | { code: '.foo { border: 0; }' }, 14 | { code: '.foo { border: $foo; }' }, 15 | { code: '.foo { border: 1px solid $bar; }' }, 16 | { code: '.foo { border: 1px solid $bar; }' }, 17 | { code: '.foo { border: 1px solid namespace.$bar; }' }, 18 | { code: '.foo { border: 1px solid @bar; }' }, 19 | { code: '.foo { border: 1px solid var(--bar); }' }, 20 | { code: '.foo { border: 1px solid var(--bar, fallback); }' }, 21 | { code: '.foo { border: 1px solid var(--bar, fallback, fallback2); }' }, 22 | { 23 | code: `.foo { border: 1px solid var( 24 | --bar, 25 | fallback 26 | ); }`, 27 | }, 28 | { 29 | code: `.foo { border: 1px solid var( 30 | --bar, 31 | fallback, 32 | fallback2 33 | ); }`, 34 | }, 35 | { code: '.foo { border: 1px solid -$bar; }' }, 36 | { code: '.foo { border: 1px solid -namespace.$bar; }' }, 37 | { code: '.foo { border: 1px solid -@bar; }' }, 38 | { code: '.foo { border: 1px solid -var(--bar); }' }, 39 | { code: '.foo { border: 1px solid spacing(); }' }, 40 | { code: '.foo { border: 1px solid map-get($bar, baz); }' }, 41 | { code: '.foo { border: 1px solid map-get(namespace.$bar, baz); }' }, 42 | { code: '.foo { border: 1px solid darken(#fff, 10%); }' }, 43 | { code: '.foo { border: 1px solid color(#fff, lighten(10%)); }' }, 44 | { 45 | code: `.foo { border: 1px solid map-get( 46 | $bar, 47 | baz) 48 | ; }`, 49 | }, 50 | { 51 | code: `.foo { border: 1px solid map-get( 52 | namespace.$bar, 53 | baz) 54 | ; }`, 55 | }, 56 | { 57 | code: `.foo { border: 1px solid darken( 58 | #fff, 59 | 10%) 60 | ; }`, 61 | }, 62 | { 63 | code: `.foo { border: 1px solid color( 64 | #fff, 65 | lighten(10%)) 66 | ; }`, 67 | }, 68 | 69 | { code: '.foo { background: $bar; }' }, 70 | { code: '.foo { background: $bar; }' }, 71 | { code: '.foo { background: namespace.$bar; }' }, 72 | { code: '.foo { background: @bar; }' }, 73 | { code: '.foo { background: var(--bar); }' }, 74 | { code: '.foo { background: var(--bar, fallback); }' }, 75 | { code: '.foo { background: var(--bar, fallback, fallback2); }' }, 76 | { 77 | code: `.foo { background: var( 78 | --bar, 79 | fallback 80 | ); }`, 81 | }, 82 | { 83 | code: `.foo { background: var( 84 | --bar, 85 | fallback, 86 | fallback2 87 | ); }`, 88 | }, 89 | { code: '.foo { background: -$bar; }' }, 90 | { code: '.foo { background: -namespace.$bar; }' }, 91 | { code: '.foo { background: -@bar; }' }, 92 | { code: '.foo { background: -var(--bar); }' }, 93 | { code: '.foo { background: spacing(); }' }, 94 | { code: '.foo { background: map-get($bar, baz); }' }, 95 | { code: '.foo { background: map-get(namespace.$bar, baz); }' }, 96 | { code: '.foo { background: darken(#fff, 10%); }' }, 97 | { code: '.foo { background: color(#fff, lighten(10%)); }' }, 98 | { 99 | code: `.foo { background: map-get( 100 | $bar, 101 | baz) 102 | ; }`, 103 | }, 104 | { 105 | code: `.foo { background: map-get( 106 | namespace.$bar, 107 | baz) 108 | ; }`, 109 | }, 110 | { 111 | code: `.foo { background: darken( 112 | #fff, 113 | 10%) 114 | ; }`, 115 | }, 116 | { 117 | code: `.foo { background: color( 118 | #fff, 119 | lighten(10%)) 120 | ; }`, 121 | }, 122 | { code: '.foo { background: no-repeat; }' }, 123 | ], 124 | 125 | reject: [ 126 | { 127 | code: '.foo { scrollbar-color: $foo #fff; }', 128 | message: `Expected variable or function for "#fff" of "scrollbar-color" (${ruleName})`, 129 | line: 1, 130 | column: 8, 131 | }, 132 | { 133 | code: '.foo { scrollbar-color: transparent @bar; }', 134 | message: `Expected variable or function for "transparent" of "scrollbar-color" (${ruleName})`, 135 | line: 1, 136 | column: 8, 137 | }, 138 | { 139 | code: '.foo { border: 1px solid #fff; }', 140 | message: `Expected variable or function for "#fff" of "border" (${ruleName})`, 141 | line: 1, 142 | column: 8, 143 | }, 144 | { 145 | code: '.foo { border: 1px solid red; }', 146 | message: `Expected variable or function for "red" of "border" (${ruleName})`, 147 | line: 1, 148 | column: 8, 149 | }, 150 | { 151 | code: '.foo { background: #fff; }', 152 | message: `Expected variable or function for "#fff" of "background" (${ruleName})`, 153 | line: 1, 154 | column: 8, 155 | }, 156 | { 157 | code: '.foo { background: red; }', 158 | message: `Expected variable or function for "red" of "background" (${ruleName})`, 159 | line: 1, 160 | column: 8, 161 | }, 162 | ], 163 | }); 164 | 165 | testRule({ 166 | ruleName, 167 | 168 | config: [ 169 | '/color/', 170 | { 171 | ignoreVariables: false, 172 | ignoreKeywords: 'transparent', 173 | expandShorthand: true, 174 | }, 175 | ], 176 | 177 | accept: [ 178 | { code: '.foo { scrollbar-color: transparent transparent; }' }, 179 | { code: '.foo { scrollbar-color: transparent darken(#fff, 10%); }' }, 180 | { code: '.foo { scrollbar-color: darken(#fff, 10%) darken(#fff, 10%); }' }, 181 | { code: '.foo { scrollbar-color: darken(#fff, 10%) transparent; }' }, 182 | { code: '.foo { border: 0; }' }, 183 | { code: '.foo { border: transparent; }' }, 184 | { code: '.foo { border: 1px solid transparent; }' }, 185 | { code: '.foo { background: transparent; }' }, 186 | { code: '.foo { background: no-repeat; }' }, 187 | ], 188 | 189 | reject: [ 190 | { 191 | code: '.foo { scrollbar-color: transparent $foo; }', 192 | message: `Expected function or keyword for "$foo" of "scrollbar-color" (${ruleName})`, 193 | line: 1, 194 | column: 8, 195 | }, 196 | { 197 | code: '.foo { scrollbar-color: var(--bar) darken(#fff, 10%); }', 198 | message: `Expected function or keyword for "var(--bar)" of "scrollbar-color" (${ruleName})`, 199 | line: 1, 200 | column: 8, 201 | }, 202 | { 203 | code: '.foo { border: $foo; }', 204 | message: `Expected function or keyword for "$foo" of "border" (${ruleName})`, 205 | line: 1, 206 | column: 8, 207 | }, 208 | { 209 | code: '.foo { border: 1px solid $bar; }', 210 | message: `Expected function or keyword for "$bar" of "border" (${ruleName})`, 211 | line: 1, 212 | column: 8, 213 | }, 214 | { 215 | code: '.foo { border: 1px solid namespace.$bar; }', 216 | message: `Expected function or keyword for "namespace.$bar" of "border" (${ruleName})`, 217 | line: 1, 218 | column: 8, 219 | }, 220 | { 221 | code: '.foo { border: 1px solid @bar; }', 222 | message: `Expected function or keyword for "@bar" of "border" (${ruleName})`, 223 | line: 1, 224 | column: 8, 225 | }, 226 | { 227 | code: '.foo { border: 1px solid var(--bar); }', 228 | message: `Expected function or keyword for "var(--bar)" of "border" (${ruleName})`, 229 | line: 1, 230 | column: 8, 231 | }, 232 | { 233 | code: '.foo { background: $bar; }', 234 | message: `Expected function or keyword for "$bar" of "background" (${ruleName})`, 235 | line: 1, 236 | column: 8, 237 | }, 238 | { 239 | code: '.foo { background: namespace.$bar; }', 240 | message: `Expected function or keyword for "namespace.$bar" of "background" (${ruleName})`, 241 | line: 1, 242 | column: 8, 243 | }, 244 | { 245 | code: '.foo { background: @bar; }', 246 | message: `Expected function or keyword for "@bar" of "background" (${ruleName})`, 247 | line: 1, 248 | column: 8, 249 | }, 250 | { 251 | code: '.foo { background: var(--bar); }', 252 | message: `Expected function or keyword for "var(--bar)" of "background" (${ruleName})`, 253 | line: 1, 254 | column: 8, 255 | }, 256 | ], 257 | }); 258 | 259 | testRule({ 260 | ruleName, 261 | 262 | config: [ 263 | '/margin-?(top|right|bottom|left)?/', 264 | { 265 | ignoreValues: ['0', 'auto'], 266 | expandShorthand: true, 267 | }, 268 | ], 269 | 270 | accept: [ 271 | { code: '.foo { margin: auto; }' }, 272 | { code: '.foo { margin: 0; }' }, 273 | { code: '.foo { margin: 0 auto; }' }, 274 | { code: '.foo { margin: 0 auto 0; }' }, 275 | { code: '.foo { margin: 0 auto 0 auto; }' }, 276 | ], 277 | 278 | reject: [ 279 | { 280 | code: '.foo { margin: inherit; }', 281 | message: `Expected variable, function or keyword for "inherit" of "margin" (${ruleName})`, 282 | line: 1, 283 | column: 8, 284 | }, 285 | ], 286 | }); 287 | 288 | testRule({ 289 | ruleName, 290 | 291 | config: [ 292 | '/color/', 293 | { 294 | expandShorthand: false, 295 | }, 296 | ], 297 | 298 | accept: [ 299 | { code: '.foo { border: 1px solid #fff; }' }, 300 | { code: '.foo { border: 1px solid red; }' }, 301 | { code: '.foo { background: #fff; }' }, 302 | { code: '.foo { background: red; }' }, 303 | { code: '.foo { background: no-repeat; }' }, 304 | ], 305 | }); 306 | 307 | testRule({ 308 | ruleName, 309 | 310 | config: [ 311 | '/color/', 312 | { 313 | expandShorthand: 'foo', 314 | }, 315 | ], 316 | 317 | reject: [ 318 | { 319 | code: '.foo { border: red; }', 320 | message: `Invalid option "{"expandShorthand":"foo"}" for rule "${ruleName}"`, 321 | }, 322 | ], 323 | }); 324 | 325 | testRule({ 326 | ruleName, 327 | 328 | config: [ 329 | '/color/', 330 | { 331 | recurseLonghand: 'foo', 332 | }, 333 | ], 334 | 335 | reject: [ 336 | { 337 | code: '.foo { border: red; }', 338 | message: `Invalid option "{"recurseLonghand":"foo"}" for rule "${ruleName}"`, 339 | }, 340 | ], 341 | }); 342 | -------------------------------------------------------------------------------- /test/single-keyword.js: -------------------------------------------------------------------------------- 1 | import { ruleName } from '../src'; 2 | 3 | // ignore single keyword 4 | testRule({ 5 | ruleName, 6 | 7 | config: [ 8 | 'color', 9 | { 10 | ignoreKeywords: 'transparent', 11 | }, 12 | ], 13 | 14 | accept: [ 15 | { code: '.foo { color: transparent; }' }, 16 | { code: '.foo { color: $color; }' }, 17 | { code: '.foo { color: spacing(); }' }, 18 | { code: '.foo { color: transparent; } .bar { color: transparent; }' }, 19 | ], 20 | 21 | reject: [ 22 | { 23 | code: '.foo { color: inherit; }', 24 | message: `Expected variable, function or keyword for "inherit" of "color" (${ruleName})`, 25 | line: 1, 26 | column: 8, 27 | }, 28 | { 29 | code: '.foo { color: transparent; } .bar { color: transparent; } .baz { color: inherit; }', 30 | message: `Expected variable, function or keyword for "inherit" of "color" (${ruleName})`, 31 | line: 1, 32 | column: 66, 33 | }, 34 | ], 35 | }); 36 | 37 | testRule({ 38 | ruleName, 39 | 40 | config: [ 41 | '/color/', 42 | { 43 | ignoreKeywords: 'transparent', 44 | }, 45 | ], 46 | 47 | accept: [ 48 | { code: '.foo { scrollbar-color: var(--color) transparent; }' }, 49 | { code: '.foo { scrollbar-color: $color transparent; }' }, 50 | { code: '.foo { scrollbar-color: transparent @color; }' }, 51 | { code: '.foo { scrollbar-color: transparent darken(#fff, 10%); }' }, 52 | { 53 | code: '.foo { scrollbar-color: transparent darken(var(--color), 10%); }', 54 | }, 55 | { code: '.foo { border-color: $color; }' }, 56 | ], 57 | 58 | reject: [ 59 | { 60 | code: '.foo { scrollbar-color: var(--color) inherit; }', 61 | message: `Expected variable, function or keyword for "inherit" of "scrollbar-color" (${ruleName})`, 62 | line: 1, 63 | column: 8, 64 | }, 65 | { 66 | code: '.foo { color: transparent; } .bar { color: transparent; } .baz { color: inherit; }', 67 | message: `Expected variable, function or keyword for "inherit" of "color" (${ruleName})`, 68 | line: 1, 69 | column: 66, 70 | }, 71 | ], 72 | }); 73 | 74 | testRule({ 75 | ruleName, 76 | 77 | config: [ 78 | 'color', 79 | { 80 | ignoreKeywords: true, 81 | }, 82 | ], 83 | 84 | reject: [ 85 | { 86 | code: '.foo { color: red; }', 87 | message: `Invalid option "{"ignoreKeywords":true}" for rule "${ruleName}"`, 88 | }, 89 | ], 90 | }); 91 | -------------------------------------------------------------------------------- /test/single-value.js: -------------------------------------------------------------------------------- 1 | import { ruleName } from '../src'; 2 | 3 | // ignore single value 4 | testRule({ 5 | ruleName, 6 | 7 | config: [ 8 | 'color', 9 | { 10 | ignoreValues: 'transparent', 11 | }, 12 | ], 13 | 14 | accept: [{ code: '.foo { color: transparent; }' }], 15 | 16 | reject: [ 17 | { 18 | code: '.foo { color: inherit; }', 19 | message: `Expected variable, function or keyword for "inherit" of "color" (${ruleName})`, 20 | line: 1, 21 | column: 8, 22 | }, 23 | ], 24 | }); 25 | 26 | testRule({ 27 | ruleName, 28 | 29 | config: [ 30 | '/color/', 31 | { 32 | ignoreValues: 'transparent', 33 | }, 34 | ], 35 | 36 | accept: [ 37 | { code: '.foo { scrollbar-color: var(--color) transparent; }' }, 38 | { code: '.foo { scrollbar-color: $color transparent; }' }, 39 | { code: '.foo { scrollbar-color: transparent @color; }' }, 40 | { code: '.foo { scrollbar-color: transparent darken(#fff, 10%); }' }, 41 | { 42 | code: '.foo { scrollbar-color: transparent darken(var(--color), 10%); }', 43 | }, 44 | ], 45 | 46 | reject: [ 47 | { 48 | code: '.foo { scrollbar-color: var(--color) inherit; }', 49 | message: `Expected variable, function or keyword for "inherit" of "scrollbar-color" (${ruleName})`, 50 | line: 1, 51 | column: 8, 52 | }, 53 | ], 54 | }); 55 | 56 | // ignore single value regex 57 | testRule({ 58 | ruleName, 59 | 60 | config: [ 61 | 'color', 62 | { 63 | ignoreValues: '/^#[0-9a-fA-F]{3,6}$/', 64 | }, 65 | ], 66 | 67 | accept: [ 68 | { code: '.foo { color: #fff; }' }, 69 | { code: '.foo { color: #ffffff; }' }, 70 | ], 71 | 72 | reject: [ 73 | { 74 | code: '.foo { color: inherit; }', 75 | message: `Expected variable, function or keyword for "inherit" of "color" (${ruleName})`, 76 | line: 1, 77 | column: 8, 78 | }, 79 | ], 80 | }); 81 | 82 | // ignore single value regex with i flag 83 | testRule({ 84 | ruleName, 85 | 86 | config: [ 87 | 'color', 88 | { 89 | ignoreValues: '/^red$/i', 90 | }, 91 | ], 92 | 93 | accept: [ 94 | { code: '.foo { color: red; }' }, 95 | { code: '.foo { color: Red; }' }, 96 | { code: '.foo { color: REd; }' }, 97 | { code: '.foo { color: RED; }' }, 98 | { code: '.foo { color: rED; }' }, 99 | { code: '.foo { color: reD; }' }, 100 | { code: '.foo { color: $color; }' }, 101 | { code: '.foo { color: spacing(); }' }, 102 | { code: '.foo { color: red; } .bar { color: RED; }' }, 103 | ], 104 | 105 | reject: [ 106 | { 107 | code: '.foo { color: inherit; }', 108 | message: `Expected variable, function or keyword for "inherit" of "color" (${ruleName})`, 109 | line: 1, 110 | column: 8, 111 | }, 112 | { 113 | code: '.foo { color: red; } .bar { color: RED; } .baz { color: inherit; }', 114 | message: `Expected variable, function or keyword for "inherit" of "color" (${ruleName})`, 115 | line: 1, 116 | column: 50, 117 | }, 118 | ], 119 | }); 120 | 121 | testRule({ 122 | ruleName, 123 | 124 | config: [ 125 | 'color', 126 | { 127 | ignoreValues: true, 128 | }, 129 | ], 130 | 131 | reject: [ 132 | { 133 | code: '.foo { color: red; }', 134 | message: `Invalid option "{"ignoreValues":true}" for rule "${ruleName}"`, 135 | }, 136 | ], 137 | }); 138 | -------------------------------------------------------------------------------- /test/skip-var-defs.js: -------------------------------------------------------------------------------- 1 | import { ruleName } from '../src'; 2 | 3 | // default config 4 | testRule({ 5 | ruleName, 6 | 7 | config: '/color/', 8 | 9 | accept: [ 10 | { code: '$color: 1px;' }, 11 | { code: '@color: 1px;' }, 12 | { code: ':root { --color: 1px; }' }, 13 | { code: '.foo { $color: 1px; }' }, 14 | { code: '.foo { @color: 1px; }' }, 15 | { code: '.foo { --color: 1px; }' }, 16 | ], 17 | 18 | reject: [ 19 | { 20 | code: '.foo { color: #fff; }', 21 | message: `Expected variable or function for "#fff" of "color" (${ruleName})`, 22 | line: 1, 23 | column: 8, 24 | }, 25 | { 26 | code: '.foo { color: red; }', 27 | message: `Expected variable or function for "red" of "color" (${ruleName})`, 28 | line: 1, 29 | column: 8, 30 | }, 31 | ], 32 | }); 33 | -------------------------------------------------------------------------------- /test/unsafe-quiet-stylelint-deprecation-warning.js: -------------------------------------------------------------------------------- 1 | import process from 'node:process'; 2 | import unsafeQuietStylelintDeprecationWarning from '../src/unsafe-quiet-stylelint-deprecation-warning'; 3 | import { ruleName } from '../src/defaults'; 4 | 5 | describe('quietContextFixDeprecationWarning', () => { 6 | afterEach(() => { 7 | jest.restoreAllMocks(); 8 | }); 9 | 10 | it('quiets context.fix deprecation warnings by message', () => { 11 | const emitWarningSpy = jest.spyOn(process, 'emitWarning'); 12 | 13 | unsafeQuietStylelintDeprecationWarning(); 14 | 15 | process.emitWarning(ruleName, { 16 | type: 'DeprecationWarning', 17 | code: 'stylelint:005', 18 | }); 19 | 20 | expect(emitWarningSpy).not.toHaveBeenCalled(); 21 | }); 22 | 23 | it('quiets context.fix deprecation warnings by options.detail', () => { 24 | const emitWarningSpy = jest.spyOn(process, 'emitWarning'); 25 | 26 | unsafeQuietStylelintDeprecationWarning(); 27 | 28 | process.emitWarning('', { 29 | type: 'DeprecationWarning', 30 | code: 'stylelint:005', 31 | detail: ruleName, 32 | }); 33 | 34 | expect(emitWarningSpy).not.toHaveBeenCalled(); 35 | }); 36 | 37 | it('quiets utils.report deprecation warnings by message', () => { 38 | const emitWarningSpy = jest.spyOn(process, 'emitWarning'); 39 | 40 | unsafeQuietStylelintDeprecationWarning(); 41 | 42 | process.emitWarning(ruleName, { 43 | type: 'DeprecationWarning', 44 | code: 'stylelint:007', 45 | }); 46 | 47 | expect(emitWarningSpy).not.toHaveBeenCalled(); 48 | }); 49 | 50 | it('quiets utils.report deprecation warnings by options.detail', () => { 51 | const emitWarningSpy = jest.spyOn(process, 'emitWarning'); 52 | 53 | unsafeQuietStylelintDeprecationWarning(); 54 | 55 | process.emitWarning('', { 56 | type: 'DeprecationWarning', 57 | code: 'stylelint:007', 58 | detail: ruleName, 59 | }); 60 | 61 | expect(emitWarningSpy).not.toHaveBeenCalled(); 62 | }); 63 | 64 | it('re-emits unrelated warnings', () => { 65 | const emitWarningSpy = jest.spyOn(process, 'emitWarning'); 66 | 67 | unsafeQuietStylelintDeprecationWarning(); 68 | 69 | process.emitWarning('foo', { 70 | type: 'DeprecationWarning', 71 | code: 'bar', 72 | }); 73 | 74 | expect(emitWarningSpy).toHaveBeenCalled(); 75 | expect(emitWarningSpy).toHaveBeenCalledTimes(1); 76 | }); 77 | }); 78 | -------------------------------------------------------------------------------- /test/values-hash.js: -------------------------------------------------------------------------------- 1 | import { ruleName } from '../src'; 2 | 3 | // ignore keywords hash 4 | testRule({ 5 | ruleName, 6 | 7 | config: [ 8 | ['/color$/', 'fill', 'z-index', 'display'], 9 | { 10 | ignoreValues: { 11 | '/color$/': ['transparent', '/^red$/i'], 12 | fill: 'inherit', 13 | 'z-index': '/^\\d+$/', 14 | '': 'initial', 15 | }, 16 | }, 17 | ], 18 | 19 | accept: [ 20 | { code: '.foo { color: transparent; }' }, 21 | { code: '.foo { color: red; }' }, 22 | { code: '.foo { color: RED; }' }, 23 | { code: '.foo { background-color: transparent; }' }, 24 | { code: '.foo { background-color: red; }' }, 25 | { code: '.foo { background-color: RED; }' }, 26 | { code: '.foo { border-color: transparent; }' }, 27 | { code: '.foo { border-color: red; }' }, 28 | { code: '.foo { border-color: RED; }' }, 29 | { code: '.foo { fill: inherit; }' }, 30 | { code: '.foo { z-index: 0; }' }, 31 | { code: '.foo { z-index: 1000; }' }, 32 | { code: '.foo { display: initial; }' }, 33 | ], 34 | 35 | reject: [ 36 | { 37 | code: '.foo { color: inherit; }', 38 | message: `Expected variable, function or keyword for "inherit" of "color" (${ruleName})`, 39 | line: 1, 40 | column: 8, 41 | }, 42 | { 43 | code: '.foo { fill: currentColor; }', 44 | message: `Expected variable, function or keyword for "currentColor" of "fill" (${ruleName})`, 45 | line: 1, 46 | column: 8, 47 | }, 48 | { 49 | code: '.foo { z-index: foo; }', 50 | message: `Expected variable, function or keyword for "foo" of "z-index" (${ruleName})`, 51 | line: 1, 52 | column: 8, 53 | }, 54 | { 55 | code: '.foo { display: block; }', 56 | message: `Expected variable, function or keyword for "block" of "display" (${ruleName})`, 57 | line: 1, 58 | column: 8, 59 | }, 60 | ], 61 | }); 62 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "emitDeclarationOnly": false, 5 | "isolatedModules": false, 6 | "noImplicitAny": false, 7 | "target": "ESNext", 8 | "module": "ESNext", 9 | "typeRoots": ["./types", "node_modules/@types"], 10 | "skipLibCheck": true, 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "emitDeclarationOnly": false, 5 | "isolatedModules": false, 6 | "noImplicitAny": true, 7 | "strictNullChecks": true, 8 | "strictPropertyInitialization": true, 9 | "strictFunctionTypes": false, 10 | "strictBindCallApply": true, 11 | "noImplicitThis": true, 12 | "esModuleInterop": true, 13 | "target": "ESNext", 14 | "module": "ESNext", 15 | "moduleResolution": "Node", 16 | "typeRoots": ["./types", "node_modules/@types"] 17 | }, 18 | } 19 | -------------------------------------------------------------------------------- /typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "entryPoints": ["src/index.ts", "src/defaults.ts", "src/lib/validation.ts"], 3 | "readme": "none", 4 | "out": "docs", 5 | "includeVersion": true 6 | } 7 | -------------------------------------------------------------------------------- /types/css-values.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'css-values'; 2 | -------------------------------------------------------------------------------- /types/shortcss.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'shortcss'; 2 | 3 | declare module 'shortcss/lib/list'; 4 | --------------------------------------------------------------------------------