@hs-web-team/eslint-config-node 4.0.2 → 4.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.githooks/commit-msg +28 -0
- package/.github/workflows/release-please.yml +44 -0
- package/.release-please-manifest.json +3 -0
- package/.stylelintrc.json +23 -1
- package/CHANGELOG.md +15 -0
- package/README.md +55 -0
- package/bin/check-peer-deps.cjs +78 -0
- package/examples/stylelint-usage.md +2 -2
- package/package.json +9 -3
- package/release-please-config.json +8 -0
- package/.github/workflows/release.yml +0 -34
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
commit_msg=$(head -1 "$1")
|
|
4
|
+
|
|
5
|
+
# Skip merge and revert commits (auto-generated messages)
|
|
6
|
+
case "$commit_msg" in
|
|
7
|
+
Merge\ *|Revert\ *) exit 0 ;;
|
|
8
|
+
esac
|
|
9
|
+
|
|
10
|
+
pattern="^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\([a-zA-Z0-9_/-]+\))?!?: .+"
|
|
11
|
+
|
|
12
|
+
if ! echo "$commit_msg" | grep -qE "$pattern"; then
|
|
13
|
+
echo ""
|
|
14
|
+
echo "ERROR: Commit message does not follow Conventional Commits format."
|
|
15
|
+
echo ""
|
|
16
|
+
echo " Expected: type(optional-scope): description"
|
|
17
|
+
echo " Types: feat | fix | docs | style | refactor | test | chore | ci | perf | revert | build"
|
|
18
|
+
echo ""
|
|
19
|
+
echo " Examples:"
|
|
20
|
+
echo " feat: add new rule for import order"
|
|
21
|
+
echo " fix: correct comma-dangle config for browser"
|
|
22
|
+
echo " feat!: drop support for Node 18 (breaking change -> major bump)"
|
|
23
|
+
echo " feat(browser): add React 19 support"
|
|
24
|
+
echo ""
|
|
25
|
+
echo " See: https://www.conventionalcommits.org"
|
|
26
|
+
echo ""
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: Release Please
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: write
|
|
9
|
+
pull-requests: write
|
|
10
|
+
id-token: write # Required for OIDC npm publish
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
release-please:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
outputs:
|
|
16
|
+
release_created: ${{ steps.release.outputs.release_created }}
|
|
17
|
+
steps:
|
|
18
|
+
- uses: googleapis/release-please-action@v5
|
|
19
|
+
id: release
|
|
20
|
+
with:
|
|
21
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
22
|
+
|
|
23
|
+
publish:
|
|
24
|
+
needs: release-please
|
|
25
|
+
if: ${{ needs.release-please.outputs.release_created == 'true' }}
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v6
|
|
29
|
+
- uses: actions/setup-node@v6
|
|
30
|
+
with:
|
|
31
|
+
node-version: 24
|
|
32
|
+
registry-url: 'https://registry.npmjs.org'
|
|
33
|
+
- run: npm ci
|
|
34
|
+
- run: npm run build --if-present
|
|
35
|
+
- name: Publish to npm
|
|
36
|
+
run: |
|
|
37
|
+
VERSION=$(node -p "require('./package.json').version")
|
|
38
|
+
if [[ "$VERSION" =~ -next\. ]] || [[ "$VERSION" =~ -(alpha|beta|rc)\. ]]; then
|
|
39
|
+
echo "Publishing prerelease $VERSION with tag 'next'"
|
|
40
|
+
npm publish --tag next
|
|
41
|
+
else
|
|
42
|
+
echo "Publishing stable $VERSION"
|
|
43
|
+
npm publish
|
|
44
|
+
fi
|
package/.stylelintrc.json
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"extends": "stylelint-config-standard-scss",
|
|
3
|
+
"plugins": ["stylelint-declaration-strict-value"],
|
|
3
4
|
"rules": {
|
|
5
|
+
"scale-unlimited/declaration-strict-value": [
|
|
6
|
+
["/color/", "fill", "stroke", "font-size", "font-weight"],
|
|
7
|
+
{
|
|
8
|
+
"ignoreValues": ["inherit", "initial", "normal", "unset", "revert", "currentColor", "transparent"],
|
|
9
|
+
"message": "Expected a CSS custom property (var(--token)) or Sass variable ($var). For color opacity variants, use color-mix(in srgb, var(--token) 80%, transparent) instead of rgba().",
|
|
10
|
+
"severity": "warning"
|
|
11
|
+
}
|
|
12
|
+
],
|
|
4
13
|
"length-zero-no-unit": null,
|
|
5
14
|
"declaration-empty-line-before": null,
|
|
6
15
|
"no-empty-source": null,
|
|
@@ -11,7 +20,13 @@
|
|
|
11
20
|
}
|
|
12
21
|
],
|
|
13
22
|
"scss/dollar-variable-pattern": null,
|
|
14
|
-
"selector-class-pattern":
|
|
23
|
+
"selector-class-pattern": [
|
|
24
|
+
"^-?[a-z0-9]([a-z0-9]|-(?!-))*$",
|
|
25
|
+
{
|
|
26
|
+
"message": "Class names should only contain lowercase alphanumeric characters and hyphens, with no consecutive hyphens",
|
|
27
|
+
"severity": "warning"
|
|
28
|
+
}
|
|
29
|
+
],
|
|
15
30
|
"declaration-block-no-redundant-longhand-properties": null,
|
|
16
31
|
"alpha-value-notation": null,
|
|
17
32
|
"scss/percent-placeholder-pattern": null,
|
|
@@ -33,6 +48,13 @@
|
|
|
33
48
|
{
|
|
34
49
|
"camelCaseSvgKeywords": true
|
|
35
50
|
}
|
|
51
|
+
],
|
|
52
|
+
"selector-disallowed-list": [
|
|
53
|
+
["/(?:^|[\\s>+~])\\s*\\.-[a-z]/i"],
|
|
54
|
+
{
|
|
55
|
+
"message": "Modifier classes (starting with '-') must not be standalone selectors; always combine with a base class (e.g., .prefix-element.-modifier or &.-modifier in nested rules)",
|
|
56
|
+
"severity": "error"
|
|
57
|
+
}
|
|
36
58
|
]
|
|
37
59
|
}
|
|
38
60
|
}
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [4.2.1](https://github.com/HubSpotWebTeam/wt-eslint-node/compare/v4.2.0...v4.2.1) (2026-06-05)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* re-trigger publish after release-please CI fix ([45fe949](https://github.com/HubSpotWebTeam/wt-eslint-node/commit/45fe94930c06d61e6f8f3015bc4e6518e187aaa1))
|
|
9
|
+
|
|
10
|
+
## [4.2.0](https://github.com/HubSpotWebTeam/wt-eslint-node/compare/v4.1.0...v4.2.0) (2026-06-05)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* warn on hardcoded color, font-size, and font-weight values ([#37](https://github.com/HubSpotWebTeam/wt-eslint-node/issues/37)) ([783a320](https://github.com/HubSpotWebTeam/wt-eslint-node/commit/783a320a3d0e858cd370670be452aaa847ba9c39))
|
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@ This package provides ESLint rules and configurations for **Hubspot Marketing We
|
|
|
13
13
|
- [Accessibility Testing](#accessibility-testing-optional)
|
|
14
14
|
- [Where to use it](#where-to-use-it)
|
|
15
15
|
- [Using the Prettier Scripts](#using-the-prettier-scripts)
|
|
16
|
+
- [Contributing](#contributing)
|
|
16
17
|
<!-- index-end -->
|
|
17
18
|
|
|
18
19
|
## Node.js Setup
|
|
@@ -199,3 +200,57 @@ See [MIGRATION-V2.md](./docs/MIGRATION-V2.md)
|
|
|
199
200
|
## Migration from v2 to v3
|
|
200
201
|
|
|
201
202
|
See [MIGRATION-V3.md](./docs/MIGRATION-V3.md)
|
|
203
|
+
|
|
204
|
+
## Contributing
|
|
205
|
+
|
|
206
|
+
### Conventional Commits
|
|
207
|
+
|
|
208
|
+
This repo uses [Conventional Commits](https://www.conventionalcommits.org) for all commit messages. A `commit-msg` git hook validates the format automatically — run `npm install` once to activate it.
|
|
209
|
+
|
|
210
|
+
**Format:** `type(optional-scope): description`
|
|
211
|
+
|
|
212
|
+
| Type | Use for | Version bump |
|
|
213
|
+
|------|---------|-------------|
|
|
214
|
+
| `feat` | New feature or config rule | Minor (`4.0.0` → `4.1.0`) |
|
|
215
|
+
| `fix` | Bug fix or rule correction | Patch (`4.0.0` → `4.0.1`) |
|
|
216
|
+
| `feat!` or `BREAKING CHANGE:` footer | Breaking API/config change | Major (`4.0.0` → `5.0.0`) |
|
|
217
|
+
| `chore` | Dependency updates, tooling | No release |
|
|
218
|
+
| `docs` | Documentation only | No release |
|
|
219
|
+
| `refactor` | Internal restructuring | No release |
|
|
220
|
+
| `ci` | CI/CD changes | No release |
|
|
221
|
+
| `test` | Test changes | No release |
|
|
222
|
+
|
|
223
|
+
**Examples:**
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
feat: add import/order rule to Node config
|
|
227
|
+
fix: align browser comma-dangle with prettier defaults
|
|
228
|
+
feat(browser): add React 19 peer dep support
|
|
229
|
+
feat!: drop Node 18 support — requires Node 24+
|
|
230
|
+
chore: bump typescript-eslint to v8.60
|
|
231
|
+
docs: update Cypress usage examples
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
A breaking change can also be indicated by adding a `BREAKING CHANGE:` footer to any commit type:
|
|
235
|
+
|
|
236
|
+
```
|
|
237
|
+
feat: remove deprecated stylelint rules
|
|
238
|
+
|
|
239
|
+
BREAKING CHANGE: Removed rules that were dropped in stylelint-scss@7.
|
|
240
|
+
Projects relying on those rules must update their configs before upgrading.
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Release Process
|
|
244
|
+
|
|
245
|
+
Releases are automated via [release-please](https://github.com/googleapis/release-please). No manual version bumping or GitHub release creation is needed.
|
|
246
|
+
|
|
247
|
+
**How it works:**
|
|
248
|
+
|
|
249
|
+
1. Merge PRs to `main` using conventional commit messages (see above).
|
|
250
|
+
2. After each merge, release-please opens or updates a **Release PR** (titled `chore(main): release X.Y.Z`) that accumulates all unreleased changes, bumps `package.json`, and generates a `CHANGELOG.md` entry.
|
|
251
|
+
3. When you are ready to publish, **merge the Release PR**.
|
|
252
|
+
4. release-please creates a GitHub release and git tag automatically.
|
|
253
|
+
5. The `release.yml` workflow fires on the new release and publishes to npm.
|
|
254
|
+
|
|
255
|
+
**To release a prerelease (`-next.N`):**
|
|
256
|
+
Update the version in `package.json` manually on a branch (e.g. `4.1.0-next.0`) and create a GitHub release by hand — the existing `release.yml` workflow will publish it with the `next` tag on npm. Prereleases are not yet managed by release-please in this repo.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const projectRoot = process.env.INIT_CWD || process.env.npm_config_local_prefix;
|
|
7
|
+
|
|
8
|
+
// Skip if we can't determine the consuming project's root, or if postinstall
|
|
9
|
+
// is running inside this package's own development environment.
|
|
10
|
+
if (!projectRoot || projectRoot === path.resolve(__dirname, '..')) {
|
|
11
|
+
process.exit(0);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const ownPkg = require('../package.json');
|
|
15
|
+
|
|
16
|
+
const stylelintPeers = Object.entries(ownPkg.peerDependencies || {}).filter(([name]) =>
|
|
17
|
+
name.startsWith('stylelint')
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
// Extracts the minimum required major version from a semver range like ^17.0.0 or >=17.1.1.
|
|
21
|
+
const minMajor = (range) => {
|
|
22
|
+
const match = range.match(/(\d+)/);
|
|
23
|
+
return match ? parseInt(match[1], 10) : 0;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const isInstalled = (pkg) =>
|
|
27
|
+
fs.existsSync(path.join(projectRoot, 'node_modules', pkg, 'package.json'));
|
|
28
|
+
|
|
29
|
+
// Only warn about missing stylelint plugins if stylelint itself is installed —
|
|
30
|
+
// consumers who don't use stylelint at all don't need any of these.
|
|
31
|
+
const stylelintInUse = isInstalled('stylelint');
|
|
32
|
+
|
|
33
|
+
const outdated = [];
|
|
34
|
+
const missing = [];
|
|
35
|
+
|
|
36
|
+
for (const [pkg, requiredRange] of stylelintPeers) {
|
|
37
|
+
const pkgJsonPath = path.join(projectRoot, 'node_modules', pkg, 'package.json');
|
|
38
|
+
|
|
39
|
+
if (!fs.existsSync(pkgJsonPath)) {
|
|
40
|
+
if (stylelintInUse && pkg !== 'stylelint') {
|
|
41
|
+
missing.push({ pkg, requiredRange });
|
|
42
|
+
}
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const { version } = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8'));
|
|
47
|
+
const installedMajor = parseInt(version.split('.')[0], 10);
|
|
48
|
+
|
|
49
|
+
if (installedMajor < minMajor(requiredRange)) {
|
|
50
|
+
outdated.push({ pkg, version, requiredRange });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (outdated.length === 0 && missing.length === 0) process.exit(0);
|
|
55
|
+
|
|
56
|
+
const pkgName = ownPkg.name;
|
|
57
|
+
|
|
58
|
+
if (missing.length > 0) {
|
|
59
|
+
console.warn(`\n⚠️ ${pkgName}: missing stylelint peer dependencies.\n`);
|
|
60
|
+
console.warn(' These packages are required for stylelint to work correctly:');
|
|
61
|
+
for (const { pkg, requiredRange } of missing) {
|
|
62
|
+
console.warn(` • ${pkg} (required: ${requiredRange})`);
|
|
63
|
+
}
|
|
64
|
+
const installCmd = missing.map(({ pkg, requiredRange }) => `${pkg}@"${requiredRange}"`).join(' ');
|
|
65
|
+
console.warn(`\n Run: npm install --save-dev ${installCmd}`);
|
|
66
|
+
console.warn(' Linting will fail without these packages.\n');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (outdated.length > 0) {
|
|
70
|
+
console.warn(`\n⚠️ ${pkgName}: outdated stylelint peer dependencies detected.\n`);
|
|
71
|
+
console.warn(' These packages are installed at versions that are no longer compatible:');
|
|
72
|
+
for (const { pkg, version, requiredRange } of outdated) {
|
|
73
|
+
console.warn(` • ${pkg}@${version} → required: ${requiredRange}`);
|
|
74
|
+
}
|
|
75
|
+
const upgradeCmd = outdated.map(({ pkg, requiredRange }) => `${pkg}@"${requiredRange}"`).join(' ');
|
|
76
|
+
console.warn(`\n Run: npm install ${upgradeCmd}`);
|
|
77
|
+
console.warn(' Failure to upgrade may cause unexpected lint errors.\n');
|
|
78
|
+
}
|
|
@@ -7,7 +7,7 @@ This package provides a shared Stylelint configuration for SCSS/CSS linting in H
|
|
|
7
7
|
1. Install the package and stylelint dependencies:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
npm install --save-dev @hs-web-team/eslint-config-node stylelint stylelint-config-standard-scss
|
|
10
|
+
npm install --save-dev @hs-web-team/eslint-config-node stylelint stylelint-config-standard-scss stylelint-declaration-strict-value
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
## Usage
|
|
@@ -136,7 +136,7 @@ To override rules for your project, add them to your `.stylelintrc.json`:
|
|
|
136
136
|
If you get a module not found error, ensure you have installed all dependencies:
|
|
137
137
|
|
|
138
138
|
```bash
|
|
139
|
-
npm install --save-dev stylelint stylelint-config-standard-scss
|
|
139
|
+
npm install --save-dev stylelint stylelint-config-standard-scss stylelint-declaration-strict-value
|
|
140
140
|
```
|
|
141
141
|
|
|
142
142
|
### Conflicts with Prettier
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hs-web-team/eslint-config-node",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.1",
|
|
4
4
|
"description": "HubSpot Marketing WebTeam shared configurations for ESLint, Prettier, Stylelint, and Cypress",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -29,8 +29,10 @@
|
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
|
+
"postinstall": "node bin/check-peer-deps.cjs",
|
|
32
33
|
"lint": "npx eslint -c ./index.js *.js --fix",
|
|
33
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
34
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
35
|
+
"prepare": "git rev-parse --git-dir > /dev/null 2>&1 && git config core.hooksPath .githooks || true"
|
|
34
36
|
},
|
|
35
37
|
"engines": {
|
|
36
38
|
"node": ">=24"
|
|
@@ -82,7 +84,8 @@
|
|
|
82
84
|
"cypress": "^15.16.0",
|
|
83
85
|
"stylelint": "^17.1.1",
|
|
84
86
|
"stylelint-config-standard": "^40.0.0",
|
|
85
|
-
"stylelint-config-standard-scss": "^17.0.0"
|
|
87
|
+
"stylelint-config-standard-scss": "^17.0.0",
|
|
88
|
+
"stylelint-declaration-strict-value": "^1.11.1"
|
|
86
89
|
},
|
|
87
90
|
"peerDependenciesMeta": {
|
|
88
91
|
"stylelint": {
|
|
@@ -94,6 +97,9 @@
|
|
|
94
97
|
"stylelint-config-standard-scss": {
|
|
95
98
|
"optional": true
|
|
96
99
|
},
|
|
100
|
+
"stylelint-declaration-strict-value": {
|
|
101
|
+
"optional": true
|
|
102
|
+
},
|
|
97
103
|
"cypress": {
|
|
98
104
|
"optional": true
|
|
99
105
|
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
name: Publish Package to npmjs
|
|
2
|
-
on:
|
|
3
|
-
release:
|
|
4
|
-
types: [created]
|
|
5
|
-
|
|
6
|
-
permissions:
|
|
7
|
-
id-token: write # Required for OIDC
|
|
8
|
-
contents: read
|
|
9
|
-
|
|
10
|
-
jobs:
|
|
11
|
-
build:
|
|
12
|
-
runs-on: ubuntu-latest
|
|
13
|
-
steps:
|
|
14
|
-
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
|
15
|
-
- uses: actions/checkout@v6
|
|
16
|
-
- uses: actions/setup-node@v6
|
|
17
|
-
with:
|
|
18
|
-
node-version: 24
|
|
19
|
-
registry-url: 'https://registry.npmjs.org'
|
|
20
|
-
- run: npm ci
|
|
21
|
-
- run: npm run build --if-present
|
|
22
|
-
- name: Publish to npm
|
|
23
|
-
run: |
|
|
24
|
-
VERSION=$(node -p "require('./package.json').version")
|
|
25
|
-
if [[ "$VERSION" =~ -next\. ]]; then
|
|
26
|
-
echo "Publishing prerelease version $VERSION with tag 'next'"
|
|
27
|
-
npm publish --tag next
|
|
28
|
-
elif [[ "$VERSION" =~ -(alpha|beta|rc)\. ]]; then
|
|
29
|
-
echo "Publishing prerelease version $VERSION with tag 'next'"
|
|
30
|
-
npm publish --tag next
|
|
31
|
-
else
|
|
32
|
-
echo "Publishing stable version $VERSION"
|
|
33
|
-
npm publish
|
|
34
|
-
fi
|