feat(useBooleanState): support lazy initialization for initial value … #1362
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Integration | |
| on: | |
| push: | |
| branches: | |
| - main | |
| pull_request: | |
| branches: | |
| - main | |
| jobs: | |
| quality: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| command: ['format', 'lint', 'type', 'docs', 'skill', 'codemod'] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Enable Corepack | |
| run: corepack enable | |
| - name: Set up Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version-file: '.nvmrc' | |
| cache: 'yarn' | |
| - name: Install dependencies | |
| run: yarn install | |
| - name: Run test:${{ matrix.command }} | |
| run: yarn run test:${{ matrix.command }} | |
| spec: | |
| name: spec (node ${{ matrix.node }}) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| node: ['22', '24'] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Enable Corepack | |
| run: corepack enable | |
| - name: Set up Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: ${{ matrix.node }} | |
| cache: 'yarn' | |
| - name: Install dependencies | |
| run: yarn install | |
| - name: Run test:coverage | |
| run: yarn run test:coverage | |
| - name: Upload coverage reports to Codecov | |
| if: ${{ matrix.node == '24' }} | |
| uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 | |
| with: | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| files: ./packages/react-simplikit/coverage/coverage-final.json | |
| spec-compiled: | |
| name: spec (react compiler compiled) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Enable Corepack | |
| run: corepack enable | |
| - name: Set up Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version-file: '.nvmrc' | |
| cache: 'yarn' | |
| - name: Install dependencies | |
| run: yarn install | |
| - name: Run test:compiled | |
| run: yarn run test:compiled | |
| check-changes: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| changed: ${{ steps.filter.outputs.changed }} | |
| changed_files: ${{ steps.filter.outputs.changed_files }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Enable Corepack | |
| run: corepack enable | |
| - name: Set up Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version-file: '.nvmrc' | |
| cache: 'yarn' | |
| - name: Check for changes in .ts and .tsx files | |
| id: filter | |
| uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4.0.3 | |
| with: | |
| list-files: shell | |
| filters: | | |
| changed: | |
| - added|modified: | |
| - 'packages/*/src/components/**/!(index|*.spec|*.test).ts' | |
| - 'packages/*/src/components/**/!(*.spec|*.test).tsx' | |
| - 'packages/*/src/hooks/**/!(index|*.spec|*.test).ts' | |
| - 'packages/*/src/hooks/**/!(*.spec|*.test).tsx' | |
| - 'packages/*/src/utils/**/!(index|*.spec|*.test).ts' | |
| - 'packages/*/src/utils/**/!(*.spec|*.test).tsx' | |
| verify-test: | |
| runs-on: ubuntu-latest | |
| needs: check-changes | |
| if: ${{ needs.check-changes.outputs.changed == 'true' }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Enable Corepack | |
| run: corepack enable | |
| - name: Set up Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version-file: '.nvmrc' | |
| cache: 'yarn' | |
| - name: Install dependencies | |
| run: yarn install | |
| - name: Run tests and generate coverage | |
| run: yarn run test:coverage | |
| - name: Verify test coverage | |
| run: | | |
| changed_files="${{ needs.check-changes.outputs.changed_files }}" | |
| for file in $changed_files; do | |
| package_dir="${file%%/src/*}" | |
| coverage_file="$package_dir/coverage/coverage-final.json" | |
| if [ ! -f "$coverage_file" ]; then | |
| echo "Coverage file not found: $coverage_file" | |
| exit 1 | |
| fi | |
| dir_name=$(basename $(dirname "$file")) | |
| base_name=$(basename $dir_name) | |
| test_file="" | |
| for candidate in "$base_name.spec.ts" "$base_name.spec.tsx" "$base_name.test.ts" "$base_name.test.tsx"; do | |
| if [ -f "$(dirname "$file")/$candidate" ]; then | |
| test_file="$(dirname "$file")/$candidate" | |
| break | |
| fi | |
| done | |
| if [ -z "$test_file" ]; then | |
| echo "Test file missing for $base_name" | |
| exit 1 | |
| fi | |
| # Debugging: Print the file path | |
| echo "Checking coverage for: $file" | |
| # Calculate coverage percentage for each matching entry | |
| total_lines=0 | |
| covered_lines=0 | |
| # Iterate over each matching coverage data entry | |
| for entry in $(jq -c --arg base_name "$base_name" '. | to_entries[] | select(.key | contains($base_name)) | .value' "$coverage_file"); do | |
| entry_total_lines=$(echo "$entry" | jq '.s | length') | |
| entry_covered_lines=$(echo "$entry" | jq '[.s[] | select(. > 0)] | length') | |
| # Accumulate total and covered lines | |
| total_lines=$((total_lines + entry_total_lines)) | |
| covered_lines=$((covered_lines + entry_covered_lines)) | |
| done | |
| if [ "$total_lines" -eq 0 ]; then | |
| echo "No coverage data found for $base_name" | |
| exit 1 | |
| fi | |
| # Calculate overall coverage percentage | |
| coverage=$(echo "scale=2; ($covered_lines / $total_lines) * 100" | bc) | |
| # Debugging: Print accumulated total and covered lines | |
| echo "Total lines: $total_lines, Covered lines: $covered_lines" | |
| echo "Coverage: $coverage%" | |
| # Correct the condition to check if coverage is less than 100 | |
| if (( $(echo "$coverage < 100" | bc -l) )); then | |
| echo "Test coverage for $base_name is not 100%: $coverage%" | |
| exit 1 | |
| fi | |
| done | |
| verify-jsdoc: | |
| runs-on: ubuntu-latest | |
| needs: check-changes | |
| if: ${{ needs.check-changes.outputs.changed == 'true' }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Check for JSDoc comments | |
| run: | | |
| for file in ${{ needs.check-changes.outputs.changed_files }}; do | |
| dir_name=$(basename $(dirname "$file")) | |
| base_name=$(basename $dir_name) | |
| implementation="$(dirname "$file")/$base_name.ts" | |
| if [ ! -f "$implementation" ]; then | |
| implementation="$(dirname "$file")/$base_name.tsx" | |
| if [ ! -f "$implementation" ]; then | |
| echo "Implementation missing for $file" | |
| exit 1 | |
| fi | |
| fi | |
| if ! grep -q "/\*\*" "$implementation"; then | |
| echo "JSDoc comments missing in $implementation" | |
| exit 1 | |
| fi | |
| if ! grep -q "@description" "$implementation"; then | |
| echo "@description tag missing in $implementation" | |
| exit 1 | |
| fi | |
| if ! grep -q "@example" "$implementation"; then | |
| echo "@example tag missing in $implementation" | |
| exit 1 | |
| fi | |
| done | |
| verify-jsdoc-structure: | |
| runs-on: ubuntu-latest | |
| needs: check-changes | |
| if: ${{ needs.check-changes.outputs.changed == 'true' }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Enable Corepack | |
| run: corepack enable | |
| - name: Set up Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version-file: '.nvmrc' | |
| cache: 'yarn' | |
| - name: Install dependencies | |
| run: yarn install | |
| - name: Check JSDoc structure | |
| run: | | |
| for file in ${{ needs.check-changes.outputs.changed_files }}; do | |
| directory=$(basename "$(dirname "$file")") | |
| filename=$(basename $file) | |
| filename="${filename%%.*}" | |
| if [ "$directory" != "$filename" ]; then | |
| continue | |
| fi | |
| if ! grep -e "@description" "$file"; then | |
| echo "@description tag missing in $file" | |
| exit 1 | |
| fi | |
| if ! grep -e "@example" "$file"; then | |
| echo "@example tag missing in $file" | |
| exit 1 | |
| fi | |
| if grep -q "@param" "$file"; then | |
| if ! grep -q "@param {.*}" "$file"; then | |
| echo "Parameter type missing in @param tag in $file" | |
| exit 1 | |
| fi | |
| # A bracketed optional parameter may carry a default that contains spaces | |
| # (`[initialState=new Set()]`), so the name is matched as either form. | |
| if ! grep -qE "@param \{.*\} (\[[^]]*\]|[^ -]*) - .+" "$file"; then | |
| echo "Parameter description missing in @param tag in $file" | |
| exit 1 | |
| fi | |
| fi | |
| if grep -q "@returns" "$file"; then | |
| if grep -q "@returns {\\[.*:.*\\]}" "$file"; then | |
| tuple_vars=$(grep "@returns {\\[.*\\]}" "$file" | sed -E 's/.*\[(.*)\].*/\1/' | tr ',' '\n' | sed 's/^ //' | sed -E 's/([^:]): (.+)$/\1 \`\2\`/') | |
| while read -r var_type; do | |
| if ! grep -qe "- $var_type - .*;" "$file"; then | |
| echo "Missing or invalid description for tuple member with [$var_type] in $file" | |
| exit 1 | |
| fi | |
| done <<< "$tuple_vars" | |
| else | |
| if ! grep -q "@returns {.*}" "$file"; then | |
| echo "Return type missing in @returns tag in $file" | |
| exit 1 | |
| fi | |
| fi | |
| fi | |
| done | |
| verify-exports: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Check exports | |
| run: | | |
| IMPL_DIRS=("components" "hooks" "utils") | |
| ERROR_LOG="" | |
| HAS_ERROR=0 | |
| FOUND=0 | |
| # Every implementation must be exported from the package root barrel: | |
| # it is the only public entry. | |
| for pkg in packages/*/; do | |
| ROOT_INDEX="${pkg}src/index.ts" | |
| if [ ! -f "$ROOT_INDEX" ]; then | |
| continue | |
| fi | |
| for dir in "${IMPL_DIRS[@]}"; do | |
| for impl_dir in ${pkg}src/$dir/*/; do | |
| if [ ! -d "$impl_dir" ]; then | |
| continue | |
| fi | |
| impl_name=$(basename "$impl_dir") | |
| impl_index="$impl_dir/index.ts" | |
| impl_file="" | |
| if [ -f "$impl_dir$impl_name.ts" ]; then | |
| impl_file="$impl_name.ts" | |
| elif [ -f "$impl_dir$impl_name.tsx" ]; then | |
| impl_file="$impl_name.tsx" | |
| else | |
| ERROR_LOG+="❌ Implementation file not found for $impl_name\n" | |
| HAS_ERROR=1 | |
| continue | |
| fi | |
| FOUND=$((FOUND + 1)) | |
| if [ ! -f "$impl_index" ]; then | |
| ERROR_LOG+="❌ Missing index.ts in $impl_dir\n" | |
| HAS_ERROR=1 | |
| continue | |
| fi | |
| # `from` alone, not `export.*from`: prettier splits long re-exports | |
| # across lines, leaving `export {` and `} from './x.ts'` on different lines | |
| if ! grep -q "from.*['\"]\./$impl_file['\"]" "$impl_index"; then | |
| ERROR_LOG+="❌ $impl_name is not exported in $impl_index\n" | |
| HAS_ERROR=1 | |
| fi | |
| relative_path="./$dir/$impl_name/index.ts" | |
| if ! grep -q "from.*['\"]$relative_path['\"]" "$ROOT_INDEX"; then | |
| ERROR_LOG+="❌ $impl_name is not exported in $ROOT_INDEX\n" | |
| HAS_ERROR=1 | |
| fi | |
| done | |
| done | |
| done | |
| if [ "$FOUND" -eq 0 ]; then | |
| echo "🚨 Scanned 0 implementations — the paths in this check no longer match the repository layout." | |
| exit 1 | |
| fi | |
| echo "Scanned $FOUND implementations." | |
| if [ $HAS_ERROR -eq 1 ]; then | |
| echo -e "\n🚨 Export Validation Errors:\n" | |
| echo -e "$ERROR_LOG" | |
| echo -e "\nPlease fix the above export issues." | |
| exit 1 | |
| else | |
| echo "✅ All exports are valid!" | |
| fi | |
| verify-compiler: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Enable Corepack | |
| run: corepack enable | |
| - name: Set up Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version-file: '.nvmrc' | |
| cache: 'yarn' | |
| - name: Install dependencies | |
| run: yarn install | |
| - name: Verify React Compiler compatibility | |
| run: yarn verify:compiler | |
| verify-pack: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Enable Corepack | |
| run: corepack enable | |
| - name: Set up Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version-file: '.nvmrc' | |
| cache: 'yarn' | |
| - name: Install dependencies | |
| run: yarn install | |
| - name: Verify packaging | |
| run: yarn verify:pack | |
| verify-examples: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Enable Corepack | |
| run: corepack enable | |
| - name: Set up Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version-file: '.nvmrc' | |
| cache: 'yarn' | |
| - name: Install dependencies | |
| run: yarn install | |
| - name: Build and pack | |
| # Naming the shell adds `-o pipefail`, which the default `bash -e {0}` lacks: | |
| # without it a failed `npm pack` is masked by `tail` exiting 0, and the empty | |
| # tarball path only surfaces several steps later as a resolution error. | |
| # Scoped to this step -- `release.yml` and `verify-jsdoc` pipe through `grep`, | |
| # where a no-match exit 1 is expected and pipefail would break them. | |
| shell: bash | |
| run: | | |
| yarn workspaces foreach -Apt --include 'packages/*' run build | |
| LIB_TGZ=$(cd packages/react-simplikit && npm pack --pack-destination "$RUNNER_TEMP" | tail -1) | |
| echo "LIB_TGZ=$RUNNER_TEMP/$LIB_TGZ" >> "$GITHUB_ENV" | |
| - name: Point examples at tarballs | |
| run: | | |
| for example in examples/with-vite examples/with-nextjs; do | |
| jq --arg lib "file:$LIB_TGZ" \ | |
| '.dependencies |= with_entries( | |
| if .key == "react-simplikit" then .value = $lib | |
| else . end)' \ | |
| "$example/package.json" > "$example/package.json.tmp" | |
| mv "$example/package.json.tmp" "$example/package.json" | |
| done | |
| YARN_ENABLE_IMMUTABLE_INSTALLS=false yarn install | |
| - name: Build examples against tarballs | |
| run: | | |
| yarn workspace with-vite run build | |
| yarn workspace with-nextjs run build |