Skip to content

tooling: update pre-commit hook to stop failure propagation of no-import rule of missing dependencies #5430

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/swift-lizards-enjoy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@spectrum-web-components/icon': minor
---

fix: added missing reactive controller dependency for IconBase which was importing SystemContextResolution for context switching
Moved all linting, formatting, and static analysis logic (ESLint, Stylelint, Prettier, Lit Analyzer) into a centralized lint-staged configuration. Simplifies the pre-commit hook by delegating to `yarn lint-staged`, improving maintainability and consistency across contributors.
20 changes: 4 additions & 16 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,16 +1,4 @@
#!/usr/bin/env bash
bash << EOF
STAGED_FILES_TO_LINT=$(git diff --name-only --cached --diff-filter=d -- "*.ts" "*.js")
STAGED_FILES_TO_ANALYZE=$(git diff --name-only --cached --diff-filter=d -- "{packages,tools}/*/src/**/!(*.css).ts")
STAGED_CSS_FILES=$(git diff --name-only --cached --diff-filter=d -- "{packages,tools}/**/*.css")
VERSION_FILE=$(dirname "$0")/../tools/base/src/version.js

[ -z "$STAGED_FILES_TO_LINT" ] || yarn eslint -f pretty $STAGED_FILES_TO_LINT
[ -z "$STAGED_FILES_TO_ANALYZE" ] || yarn lit-analyzer $STAGED_FILES_TO_ANALYZE
[ -z "$STAGED_CSS_FILES" ] || yarn stylelint $STAGED_CSS_FILES

yarn pretty-quick --staged

yarn genversion --es6 --semi $VERSION_FILE
git add $VERSION_FILE
EOF
#!/bin/bash
set -e
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I've noticed this issue as well, however here's the documentation around why we added the bash wrapper: https://typicode.github.io/husky/how-to.html#bash

We're not currently supporting Windows so it seemed a fine compromise. The if syntax however is Bash syntax so removing that would be a potential issue. What do you suggest?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking we could migrate all these rules into a lint-staged config and just run the yarn lint-staged command here instead of all this logic. What are your thoughts? Was playing around with that here: #5393

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of migrate these in a module in a lint-staged config. More scalable. Let me update this here and test. Please feel free to add your thoughts too!

echo "Running pre-commit hook via lint-staged..."
yarn lint-staged --allow-empty
46 changes: 46 additions & 0 deletions lint-staged.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* eslint-disable no-console */
/*
Copyright 2025 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License.
*/
import { execSync } from 'child_process';

export default {
// Runs ESLint with fix on all staged JS/TS files
'*.{js,ts}': (files) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So lint-staged is great because it actually shows you the files it's running against so you don't need to echo the file list. It also enables parallelization so unless the command requires it, you don't have to pass the files in manually.

For example:

"*.js": ["eslint", "prettier --write"]

console.log('Running ESLint on:', files.join(' '));
return [`eslint --fix ${files.join(' ')}`];
},

// Runs lit-analyzer only on relevant .ts files inside src (excluding .css)
'{packages,tools}/*/src/**/!(*.css).ts': (files) => {
console.log('Running lit-analyzer on:', files.join(' '));
return [`lit-analyzer ${files.join(' ')}`];
},

// Runs stylelint with fix on all staged CSS files
'{packages,tools}/**/*.css': (files) => {
console.log('Running stylelint on:', files.join(' '));
return [`stylelint --fix ${files.join(' ')}`];
},
Comment on lines +29 to +32
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'{packages,tools}/**/*.css': (files) => {
console.log('Running stylelint on:', files.join(' '));
return [`stylelint --fix ${files.join(' ')}`];
},
'*.css': ['stylelint --fix'],

Since stylelint has rules about which css files it will run against, we can pass any css file from the list and it will only run if it matches the rules. This lets us manage the CSS rules from the stylelint config instead of having to replicate it here too.


// Formats selected staged files with Prettier
'!(*.css|*.ts)': [
'prettier --cache --no-error-on-unmatched-pattern --ignore-unknown --log-level silent --write',
],

// Generates and add version file
// This will always re-run and stage version.js
'tools/base/src/version.js': () => {
console.log('Generating version file...');
execSync('yarn genversion --es6 --semi tools/base/src/version.js');
return 'git add tools/base/src/version.js';
Comment on lines +41 to +44
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'tools/base/src/version.js': () => {
console.log('Generating version file...');
execSync('yarn genversion --es6 --semi tools/base/src/version.js');
return 'git add tools/base/src/version.js';
'tools/base/src/version.js': (file) => [
`genversion --es6 --semi ${file}`
`git add ${file}`,
],

This approach will still run them in parallel but it avoids using the exec function which is really problematic in scripts due to it's inconsistent way of returning warnings and information from the console.

},
};
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"icons": "wireit",
"icons:ui": "wireit",
"icons:workflow": "wireit",
"lint-staged": "lint-staged",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we benefit from this abstraction, can we look at just using the migration work I already put together?

https://jira.corp.adobe.com/browse/SWC-855

#5393

"lint": "run-p lint:js lint:docs lint:ts lint:css lint:packagejson",
"lint:css": "stylelint \"packages/**/*.css\" \"tools/**/*.css\"",
"lint:docs": "eslint -f pretty \"projects/documentation/**/*.ts\"",
Expand Down Expand Up @@ -175,6 +176,7 @@
"husky": "^9.0.10",
"latest-version": "^9.0.0",
"lightningcss": "1.19.0",
"lint-staged": "^15.5.1",
"lit": "^2.5.0 || ^3.1.3",
"lit-analyzer": "^2.0.3",
"lit-html": "^2.4.0 || ^3.1.3",
Expand Down
15 changes: 14 additions & 1 deletion packages/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,26 @@
"es6": true
},
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "notice", "@spectrum-web-components"],
"plugins": [
"@typescript-eslint",
"notice",
"@spectrum-web-components",
"import"
],
"extends": [
"plugin:@typescript-eslint/recommended",
"prettier",
"plugin:lit-a11y/recommended"
],
"rules": {
"import/no-extraneous-dependencies": [
"error",
{
"devDependencies": false,
"optionalDependencies": false,
"peerDependencies": false
}
],
Comment on lines +21 to +28
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a import dependency rule to check for missing direct dependencies.

"no-debugger": 2,
"no-console": [
"error",
Expand Down
3 changes: 2 additions & 1 deletion packages/icon/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@
],
"dependencies": {
"@spectrum-web-components/base": "1.6.0",
"@spectrum-web-components/iconset": "1.6.0"
"@spectrum-web-components/iconset": "1.6.0",
"@spectrum-web-components/reactive-controllers": "1.6.0"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch here

},
"devDependencies": {
"@spectrum-css/icon": "9.1.0"
Expand Down
72 changes: 72 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ __metadata:
husky: "npm:^9.0.10"
latest-version: "npm:^9.0.0"
lightningcss: "npm:1.19.0"
lint-staged: "npm:^15.5.1"
lit: "npm:^2.5.0 || ^3.1.3"
lit-analyzer: "npm:^2.0.3"
lit-html: "npm:^2.4.0 || ^3.1.3"
Expand Down Expand Up @@ -13687,6 +13688,13 @@ __metadata:
languageName: node
linkType: hard

"chalk@npm:^5.4.1":
version: 5.4.1
resolution: "chalk@npm:5.4.1"
checksum: 10c0/b23e88132c702f4855ca6d25cb5538b1114343e41472d5263ee8a37cccfccd9c4216d111e1097c6a27830407a1dc81fecdf2a56f2c63033d4dbbd88c10b0dcef
languageName: node
linkType: hard

"change-case@npm:^4.1.2":
version: 4.1.2
resolution: "change-case@npm:4.1.2"
Expand Down Expand Up @@ -14411,6 +14419,13 @@ __metadata:
languageName: node
linkType: hard

"commander@npm:^13.1.0":
version: 13.1.0
resolution: "commander@npm:13.1.0"
checksum: 10c0/7b8c5544bba704fbe84b7cab2e043df8586d5c114a4c5b607f83ae5060708940ed0b5bd5838cf8ce27539cde265c1cbd59ce3c8c6b017ed3eec8943e3a415164
languageName: node
linkType: hard

"commander@npm:^2.19.0, commander@npm:^2.20.0, commander@npm:^2.20.3, commander@npm:^2.8.1":
version: 2.20.3
resolution: "commander@npm:2.20.3"
Expand Down Expand Up @@ -23348,6 +23363,13 @@ __metadata:
languageName: node
linkType: hard

"lilconfig@npm:^3.1.3":
version: 3.1.3
resolution: "lilconfig@npm:3.1.3"
checksum: 10c0/f5604e7240c5c275743561442fbc5abf2a84ad94da0f5adc71d25e31fa8483048de3dcedcb7a44112a942fed305fd75841cdf6c9681c7f640c63f1049e9a5dcc
languageName: node
linkType: hard

"limit-spawn@npm:0.0.3":
version: 0.0.3
resolution: "limit-spawn@npm:0.0.3"
Expand Down Expand Up @@ -23378,6 +23400,26 @@ __metadata:
languageName: node
linkType: hard

"lint-staged@npm:^15.5.1":
version: 15.5.1
resolution: "lint-staged@npm:15.5.1"
dependencies:
chalk: "npm:^5.4.1"
commander: "npm:^13.1.0"
debug: "npm:^4.4.0"
execa: "npm:^8.0.1"
lilconfig: "npm:^3.1.3"
listr2: "npm:^8.2.5"
micromatch: "npm:^4.0.8"
pidtree: "npm:^0.6.0"
string-argv: "npm:^0.3.2"
yaml: "npm:^2.7.0"
bin:
lint-staged: bin/lint-staged.js
checksum: 10c0/86deddb08bf10428f2eb96c02326a9ee403360729225f0b12afb0c0f13c287a75daa01e179d86f64e3432576446d8643d204a47417296f9ef0aa56f1340ff2af
languageName: node
linkType: hard

"liquidjs@npm:^10.17.0":
version: 10.18.0
resolution: "liquidjs@npm:10.18.0"
Expand Down Expand Up @@ -23440,6 +23482,20 @@ __metadata:
languageName: node
linkType: hard

"listr2@npm:^8.2.5":
version: 8.3.2
resolution: "listr2@npm:8.3.2"
dependencies:
cli-truncate: "npm:^4.0.0"
colorette: "npm:^2.0.20"
eventemitter3: "npm:^5.0.1"
log-update: "npm:^6.1.0"
rfdc: "npm:^1.4.1"
wrap-ansi: "npm:^9.0.0"
checksum: 10c0/6b6378e28debda863d31f03ffe880a76b45c07388c74e8e0676fc957de7f2aff24fdea7f48b17d12808440f64680215c36df388c79d2b367c7866dd66f75fb09
languageName: node
linkType: hard

"lit-analyzer@npm:^2.0.3":
version: 2.0.3
resolution: "lit-analyzer@npm:2.0.3"
Expand Down Expand Up @@ -31985,6 +32041,13 @@ __metadata:
languageName: node
linkType: hard

"string-argv@npm:^0.3.2":
version: 0.3.2
resolution: "string-argv@npm:0.3.2"
checksum: 10c0/75c02a83759ad1722e040b86823909d9a2fc75d15dd71ec4b537c3560746e33b5f5a07f7332d1e3f88319909f82190843aa2f0a0d8c8d591ec08e93d5b8dec82
languageName: node
linkType: hard

"string-similarity@npm:^4.0.4":
version: 4.0.4
resolution: "string-similarity@npm:4.0.4"
Expand Down Expand Up @@ -35936,6 +35999,15 @@ __metadata:
languageName: node
linkType: hard

"yaml@npm:^2.7.0":
version: 2.7.1
resolution: "yaml@npm:2.7.1"
bin:
yaml: bin.mjs
checksum: 10c0/ee2126398ab7d1fdde566b4013b68e36930b9e6d8e68b6db356875c99614c10d678b6f45597a145ff6d63814961221fc305bf9242af8bf7450177f8a68537590
languageName: node
linkType: hard

"yargs-parser@npm:^21.1.1":
version: 21.1.1
resolution: "yargs-parser@npm:21.1.1"
Expand Down
Loading