From 3095b9ddda8f4f677d485e7941a828cd29d79f5a Mon Sep 17 00:00:00 2001 From: Shinrai Date: Sat, 1 Aug 2026 22:05:37 -0700 Subject: [PATCH] ci: adopt CLDMV @v4 workflows + vitest-runner test setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add the CLDMV @v4 staging-branch workflow set (22 workflows) + .github/dependabot.yml - Wire vitest + @cldmv/vitest-runner (OOM-safe per-file runner): .configs/vitest.config.mjs, tests/run-vitest.mjs harness, and test/coverage/ci:coverage npm scripts - Add a characterization test suite (91 tests) covering sizeofvar.js at 100% coverage - Add publishConfig.access=public - Remove the legacy non-vitest test/ fixtures and unused yargs devDependency Note: no engines.node floor — this package has no runtime dependencies and runs on old Node; the >=20.19 requirement is only the dev/test toolchain (vitest-runner), which is already enforced by the devDependencies' own engines. --- .configs/vitest.config.mjs | 27 + .github/dependabot.yml | 79 + .github/workflows/branch-retention.yml | 38 + .github/workflows/ci.yml | 310 + .github/workflows/cla.yml | 60 + .github/workflows/codeql.yml | 70 + .github/workflows/dependabot-auto-merge.yml | 54 + .github/workflows/dependency-review.yml | 34 + .github/workflows/feature-pr.yml | 59 + .github/workflows/hotfix-redirector.yml | 51 + .github/workflows/hotfixes-release.yml | 55 + .github/workflows/labeler.yml | 44 + .github/workflows/master-commit-audit.yml | 66 + .github/workflows/next-release.yml | 61 + .github/workflows/next-reset.yml | 43 + .github/workflows/pr-title-normalizer.yml | 45 + .github/workflows/publish.yml | 125 + .github/workflows/release-notify.yml | 37 + .github/workflows/scorecard.yml | 61 + .github/workflows/stale.yml | 46 + .github/workflows/tag-health.yml | 64 + .../workflows/update-major-version-tags.yml | 87 + .github/workflows/v4-bootstrap.yml | 106 + .github/workflows/welcome.yml | 38 + package-lock.json | 5697 +++++------------ package.json | 13 +- test/sizeofvar/test-array.js | 37 - test/sizeofvar/test-bool.js | 7 - test/sizeofvar/test-number.js | 24 - test/sizeofvar/test-object-complex.js | 77 - test/sizeofvar/test-object-key-length.js | 102 - test/sizeofvar/test-object-string.js | 49 - test/sizeofvar/test-object.js | 55 - test/sizeofvar/test-string.js | 26 - test/test-mem.js | 59 - tests/arrays.test.mjs | 103 + tests/booleans.test.mjs | 48 + tests/edge-types.test.mjs | 88 + tests/numbers.test.mjs | 94 + tests/objects.test.mjs | 161 + tests/random-properties.test.mjs | 154 + tests/run-vitest.mjs | 51 + tests/strings.test.mjs | 79 + 43 files changed, 3919 insertions(+), 4665 deletions(-) create mode 100644 .configs/vitest.config.mjs create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/branch-retention.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/cla.yml create mode 100644 .github/workflows/codeql.yml create mode 100644 .github/workflows/dependabot-auto-merge.yml create mode 100644 .github/workflows/dependency-review.yml create mode 100644 .github/workflows/feature-pr.yml create mode 100644 .github/workflows/hotfix-redirector.yml create mode 100644 .github/workflows/hotfixes-release.yml create mode 100644 .github/workflows/labeler.yml create mode 100644 .github/workflows/master-commit-audit.yml create mode 100644 .github/workflows/next-release.yml create mode 100644 .github/workflows/next-reset.yml create mode 100644 .github/workflows/pr-title-normalizer.yml create mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/release-notify.yml create mode 100644 .github/workflows/scorecard.yml create mode 100644 .github/workflows/stale.yml create mode 100644 .github/workflows/tag-health.yml create mode 100644 .github/workflows/update-major-version-tags.yml create mode 100644 .github/workflows/v4-bootstrap.yml create mode 100644 .github/workflows/welcome.yml delete mode 100644 test/sizeofvar/test-array.js delete mode 100644 test/sizeofvar/test-bool.js delete mode 100644 test/sizeofvar/test-number.js delete mode 100644 test/sizeofvar/test-object-complex.js delete mode 100644 test/sizeofvar/test-object-key-length.js delete mode 100644 test/sizeofvar/test-object-string.js delete mode 100644 test/sizeofvar/test-object.js delete mode 100644 test/sizeofvar/test-string.js delete mode 100644 test/test-mem.js create mode 100644 tests/arrays.test.mjs create mode 100644 tests/booleans.test.mjs create mode 100644 tests/edge-types.test.mjs create mode 100644 tests/numbers.test.mjs create mode 100644 tests/objects.test.mjs create mode 100644 tests/random-properties.test.mjs create mode 100644 tests/run-vitest.mjs create mode 100644 tests/strings.test.mjs diff --git a/.configs/vitest.config.mjs b/.configs/vitest.config.mjs new file mode 100644 index 0000000..1e65be6 --- /dev/null +++ b/.configs/vitest.config.mjs @@ -0,0 +1,27 @@ +import { defineConfig } from "vitest/config"; +import { fileURLToPath } from "node:url"; +import path from "node:path"; + +// Anchor the project root to the package directory so include/exclude work no +// matter what cwd vitest is invoked from. +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); + +export default defineConfig({ + root, + test: { + include: ["tests/**/*.test.mjs"], + exclude: ["node_modules"], + environment: "node", + testTimeout: 30000, + // "dot" keeps non-interactive CI logs to one character per test file. The + // final "Test Files X passed" / "Tests Y passed" summary is unaffected. + reporters: ["dot"], + coverage: { + provider: "v8", + // Single-file library — the only source under test is sizeofvar.js. + include: ["sizeofvar.js"], + exclude: ["**/*.json", "tests/**", "test/**"], + reporter: ["text", "html", "json-summary", "json"] + } + } +}); diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..585ad76 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,79 @@ +# +# @Project: @cldmv/.github +# @Filename: /examples/individual-repo-workflows/automation/dependabot.yml +# @Date: 2026-05-26 00:00:00 -07:00 (1782460800) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/dependabot.yml +# +# Dependabot configuration tuned for the v4 staging-branch release flow. +# +# How it fits with v4: +# - All Dependabot PRs target `next` so they pool with every other +# contributor change and batch into the next release. +# - `dependabot-auto-merge.yml` (in this same folder) auto-merges +# patch/minor bumps into `next` after CI passes — zero-touch pooling. +# Delete that workflow if you'd rather review each bump by hand. +# - Security updates are detected by `hotfix-redirector.yml` +# (release-flow-v4/) by GHSA references in the PR body and auto-promoted +# from `next` → `hotfixes` so they ship via the hotfix lane, not the +# next-batch release. No special routing needed in this config. +# +# Customize per repo: +# - Add or remove `package-ecosystem` blocks for your stack (gomod, pip, +# bundler, gradle, maven, cargo, docker, etc.). +# - Adjust `directory` if your manifests don't live at the repo root. +# - Tighten `open-pull-requests-limit` if Dependabot's noise is too much. +# - Add `allow` / `ignore` rules for specific packages. +# - Add `groups` to bundle related bumps into a single PR. + +version: 2 +updates: + # GitHub Actions: keep pinned action SHAs / version tags fresh. + - package-ecosystem: "github-actions" + directory: "/" + target-branch: "next" + schedule: + interval: "weekly" + open-pull-requests-limit: 5 + commit-message: + prefix: "deps" + # Grouped PRs cut noise: one PR per (security | patch | minor) bundle + # per week instead of N separate PRs. Security PRs still get retargeted + # to `hotfixes` by hotfix-redirector.yml when GHSA refs appear in the + # body — bundling N GHSA fixes into one PR is fine, the redirector + # only needs one match to retarget. + groups: + security: + applies-to: security-updates + patterns: ["*"] + patch: + applies-to: version-updates + update-types: ["patch"] + minor: + applies-to: version-updates + update-types: ["minor"] + + # NPM: package.json + package-lock.json updates. + # Delete this block if your repo isn't a Node project. + - package-ecosystem: "npm" + directory: "/" + target-branch: "next" + schedule: + interval: "weekly" + open-pull-requests-limit: 5 + commit-message: + prefix: "deps" + groups: + security: + applies-to: security-updates + patterns: ["*"] + patch: + applies-to: version-updates + update-types: ["patch"] + minor: + applies-to: version-updates + update-types: ["minor"] diff --git a/.github/workflows/branch-retention.yml b/.github/workflows/branch-retention.yml new file mode 100644 index 0000000..ea28875 --- /dev/null +++ b/.github/workflows/branch-retention.yml @@ -0,0 +1,38 @@ +# +# @Project: @cldmv/sizeofvar +# @Filename: /.github/workflows/branch-retention.yml +# @Date: 2026-05-20 00:00:00 -07:00 (1779606000) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/branch-retention.yml +# +# On PR merge: most branches deleted immediately; release/* keeps last 5, +# hotfix/* keeps last 3. master/main/badges/gh-pages never touched. +# +# v4 flow: feature PRs merge into `next` and hotfix PRs into `hotfixes` +# (not directly into master). next/hotfixes are in the branches: filter +# below so this workflow fires on those PR closures too — otherwise +# feat/* / fix/* / chore/* etc. would pile up on origin indefinitely. +# (Repos that haven't adopted v4 just won't see those branches; the +# extra entries in the filter are harmless.) +name: 🌿 Branch Retention + +on: + pull_request: + types: [closed] + branches: [master, main, next, hotfixes] + +permissions: + contents: write + pull-requests: read + +jobs: + retain: + if: github.event.pull_request.merged == true + uses: CLDMV/.github/.github/workflows/reusable-branch-retention.yml@v4 + secrets: + BOT_APP_CLIENT_ID: ${{ secrets.CLDMV_BOT_APP_CLIENT_ID }} + BOT_APP_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_APP_PRIVATE_KEY }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..f6c4cbb --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,310 @@ +# +# @Project: @cldmv/sizeofvar +# @Filename: /.github/workflows/ci.yml +# @Date: 2026-05-20 00:00:00 -07:00 (1779606000) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/ci.yml +name: 🧪 CI Tests & Build + +on: + # Note: do NOT add `paths:` / `paths-ignore:` at the trigger level. Doing + # that makes GitHub skip the workflow entirely for docs-only changes, which + # means `Required PR Check` never posts and the ruleset blocks the merge. + # The reusable workflow's `paths-gate` job does the same job from inside, + # and exposes a `docs_only` output so this workflow can still green-light + # the required check for docs-only PRs (see `required-check` below). The + # ignore globs themselves are passed via the `paths_ignore:` input below + # — override there if your repo needs different rules. + # + # `push` fires for branches in this repo only (forks push to their own remote, + # not ours). Branch protection on the PR reads the status check from the + # commit SHA, so this single trigger covers both pre-PR pushes and PR head + # updates without duplicating runs. + push: + # Bot-managed branches (badges, gh-pages) carry no source to test. + branches-ignore: [badges, gh-pages] + # `pull_request` covers two cases: + # - Fork PRs (push doesn't fire upstream for fork commits). + # - Release PRs from `next` / `hotfixes` → `master`. Their head SHA is + # a bot `chore: bump version` commit that workflow-ci.yml's + # `commit-gate` job filters out on the push path, so without the + # pull_request fallback the release PR's `Required PR Check` + # status never gets posted and the ruleset blocks the merge. + # `branches:` includes the v4 integration branches so PRs targeting + # `next` / `hotfixes` get CI too — feature PRs from forks would + # otherwise get nothing. Non-fork feature PRs still skip the + # pull_request `ci` job (push covers them); see the `if:` on the job. + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + branches: [master, main, next, hotfixes] + workflow_dispatch: + inputs: + debug: + description: "Enable debug logging for troubleshooting" + type: boolean + required: false + default: false + node_version: + description: "Node.js version to use (default: lts/*)" + type: string + required: false + default: "lts/*" + min_node_version: + description: "Minimum Node.js version for matrix testing (default: 20, oldest non-EOL)" + type: string + required: false + default: "20" + max_node_major: + description: "Override max Node.js major version (default: 22)" + type: string + required: false + default: "22" + lts_only_matrix: + description: "Only include even-numbered (LTS) Node.js major versions in the test matrix" + type: boolean + required: false + default: true + package_manager: + description: "Package manager (npm or yarn)" + type: string + required: false + default: "npm" + test_environment: + description: "Environment for tests (affects NODE_ENV and NODE_OPTIONS --conditions flag)" + type: string + required: false + default: "development" + # ── Coverage badge ─────────────────────────────────────────────── + enable_coverage_badge: + description: "Run the coverage + badge-push job after CI passes" + type: boolean + required: false + default: true + coverage_command: + description: "Command to run tests and generate coverage data" + type: string + required: false + default: "npm run ci:coverage" + coverage_summary_path: + description: "Path to the coverage-summary.json produced by Jest / c8" + type: string + required: false + default: "coverage/coverage-summary.json" + badges_branch: + description: "Branch where the badge JSON is published" + type: string + required: false + default: "badges" + badge_filename: + description: "Filename for the badge JSON committed to the badges branch" + type: string + required: false + default: "coverage.json" + upload_coverage_artifact: + description: "Upload the full coverage/ directory as a workflow artifact" + type: boolean + required: false + default: true + # ── Type check ────────────────────────────────────────────────── + type_check_command: + description: "Command to run type checking" + type: string + required: false + default: "npm run test:types" + skip_type_check: + description: "Skip the type-check step in the coverage-badge job" + type: boolean + required: false + default: false + default_branch: + description: "Default branch name — badge is only pushed on pushes to this branch" + type: string + required: false + default: "master" + enable_coverage_pr_comment: + description: "Inject a coverage badge into the PR description on pull request events" + type: boolean + required: false + default: true + +# Cancel superseded runs on feature branches; keep every master/main run as the +# permanent green record. Keyed on github.ref so push and pull_request events +# for the same branch share a group (the `if:` on the ci job already prevents +# non-fork PR sync from running, but the shared group guards against edge +# cases). +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/master' && github.ref != 'refs/heads/main' }} + +# Workflow-level: matches the broadest write surface the called +# `workflow-ci.yml` reaches across its branches: +# - coverage-badge: contents:write (push to `badges` branch) +# - coverage-pr-comment: pull-requests:write (edit PR description body) +# Jobs that don't need write (CI matrix, commit-gate, the mirror below) +# inherit but never exercise the surface. The mirror job overrides to +# `permissions: {}` since it's pure shell. +permissions: + contents: write + pull-requests: write + +jobs: + ci: + name: 🏗️ Continuous Integration + # Run on pull_request when: + # - The PR is from a fork (push doesn't fire upstream for fork commits). + # - The PR is a v4 release PR — head ref is `next` or `hotfixes` + # targeting `master`/`main`. Push-event CI on the head SHA is + # unreliable for these because workflow-ci.yml's `commit-gate` + # filters out the bot's `chore: bump version` commit, so without + # this fallback the release PR's `Required PR Check` never posts. + # Other (in-repo, non-release) PRs skip — the push event on the head + # branch already ran CI and posted status to the SHA. + if: | + github.event_name != 'pull_request' || + github.event.pull_request.head.repo.fork == true || + github.event.pull_request.head.ref == 'next' || + github.event.pull_request.head.ref == 'hotfixes' + uses: CLDMV/.github/.github/workflows/workflow-ci.yml@v4 + with: + package_name: "@cldmv/sizeofvar" # Required: replace with your NPM package name + # Globs that should NOT trigger the heavy CI matrix. When every changed + # file matches one of these, `docs_only=true` flows out of the reusable + # and `required-check` below posts a green Required PR Check without + # running CI. The default in the reusable matches these — override only + # if your repo needs different rules. + paths_ignore: | + **.md + docs/** + *.md + LICENSE + .gitignore + debug: ${{ github.event.inputs.debug == 'true' }} + node_version: ${{ github.event.inputs.node_version || 'lts/*' }} + min_node_version: ${{ github.event.inputs.min_node_version || '20' }} + max_node_major: ${{ github.event.inputs.max_node_major || '22' }} + # LTS-only matrix (even majors: 20, 22, 24, …) on every event. Odd majors + # (21, 23, …) are non-LTS interim releases, and the native-binding test + # toolchain (vitest 4 / rolldown / vite 8) excludes them via `engines` + # (`^20.19.0 || >=22.12.0`), so a "full matrix" on them only re-discovers a + # known toolchain gap ("Cannot find native binding") rather than a real + # per-version regression. workflow_dispatch can still opt out (set false). + lts_only_matrix: ${{ github.event.inputs.lts_only_matrix != 'false' }} + package_manager: ${{ github.event.inputs.package_manager || 'npm' }} + test_command: "npm test" # Use defaults: NODE_ENV=development, NODE_OPTIONS=--conditions=development + # test_command: "NODE_OPTIONS='--conditions=slothlet-dev' npm test" # Override NODE_OPTIONS only + # test_command: "NODE_ENV=test npm test" # Override NODE_ENV only + # test_command: "NODE_ENV=test NODE_OPTIONS='--conditions=slothlet-dev' npm test" # Override both + test_environment: ${{ github.event.inputs.test_environment || 'development' }} # Alternative to setting in test_command + build_command: "echo '✓ no build step'" + skip_performance_tests: false + skip_matrix_tests: false + + # ── Coverage badge ───────────────────────────────────────────────────── + # Runs after a successful CI build; pushes a Shields.io-compatible badge + # JSON to the `badges` branch (signed commit via bot GPG). + # Only runs on direct pushes to default_branch — PRs and feature branches + # are automatically skipped so coverage always reflects merged master code. + # Requires: the coverage_command produces coverage/coverage-summary.json + enable_coverage_badge: ${{ github.event.inputs.enable_coverage_badge != 'false' }} + default_branch: ${{ github.event.inputs.default_branch || 'master' }} # Badge only pushed when a push lands on this branch + coverage_command: ${{ github.event.inputs.coverage_command || 'npm run ci:coverage' }} + coverage_summary_path: ${{ github.event.inputs.coverage_summary_path || 'coverage/coverage-summary.json' }} + badges_branch: ${{ github.event.inputs.badges_branch || 'badges' }} + badge_filename: ${{ github.event.inputs.badge_filename || 'coverage.json' }} + upload_coverage_artifact: ${{ github.event.inputs.upload_coverage_artifact != 'false' }} + + # ── Type check (runs inside the coverage-badge job) ──────────────────── + # Skipped deliberately: sizeofvar is a plain single-file CommonJS library + # with no TypeScript sources and no shipped/generated type declarations, so + # there is no meaningful JS type-check to run. ESLint is the static-analysis + # net. (Revisit if the package ever ships real type definitions.) + type_check_command: ${{ github.event.inputs.type_check_command || 'npm run test:types' }} + skip_type_check: true + + # ── PR coverage badge ───────────────────────────────────────────────── + # Injects a Shields.io badge + breakdown table directly into the PR body + # on every push to the PR branch. Only fires on pull_request events; + # skipped automatically on push and workflow_dispatch. No files committed. + enable_coverage_pr_comment: ${{ github.event.inputs.enable_coverage_pr_comment != 'false' }} + + # Authentication & Bot Configuration + # The workflow supports automatic App token detection for enhanced permissions and proper attribution: + # - WITH App secrets: Operations attributed to CLDMV bot, enhanced permissions for workflow repositories + # - WITHOUT App secrets: Falls back to GitHub Actions bot with standard permissions + # Note: CI workflow currently only runs build/test jobs, but App secrets are included for consistency + # To set up App authentication, add these secrets to your repository settings: + secrets: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + # Optional: CLDMV Bot credentials for enhanced permissions and proper attribution + # If not provided, will use default GITHUB_TOKEN with GitHub Actions bot attribution + BOT_APP_CLIENT_ID: ${{ secrets.CLDMV_BOT_APP_CLIENT_ID }} + BOT_APP_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_APP_PRIVATE_KEY }} + # Required when enable_coverage_badge: true + BOT_NAME: ${{ secrets.CLDMV_BOT_NAME }} + BOT_EMAIL: ${{ secrets.CLDMV_BOT_EMAIL }} + BOT_GPG_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_GPG_PRIVATE_KEY }} + BOT_GPG_PASSPHRASE: ${{ secrets.CLDMV_BOT_GPG_PASSPHRASE }} + + # ✅ Stable check that mirrors the `ci` result so branch protection has a + # single, predictable status name to require. The push event runs on the + # same SHA that becomes the PR head, so the status attaches to the PR + # automatically — no `pull_request` round-trip needed for non-fork + # non-release PRs. + required-check: + name: ✅ Required PR Check + needs: ci + # Mirror the `ci` job's gating exactly. The four cases that run: + # 1. push events (job needs CI run) + # 2. fork PRs (push doesn't cover forks) + # 3. release PRs from `next` → master/main (push covers SHA but commit-gate skips chore-bump) + # 4. release PRs from `hotfixes` → master/main (same reason) + # In-repo feature PRs targeting `next` / `hotfixes` skip on + # pull_request — push on the head branch already posted the status + # on the SHA, and mirroring here would overwrite it. + if: | + always() && ( + github.event_name != 'pull_request' || + github.event.pull_request.head.repo.fork == true || + github.event.pull_request.head.ref == 'next' || + github.event.pull_request.head.ref == 'hotfixes' + ) + runs-on: ubuntu-latest + # Pure shell mirror — no GitHub API access. Strip the workflow's + # write defaults to zero for this job. + permissions: {} + steps: + - name: Mirror reusable result + env: + IS_MASTER_SYNC: ${{ needs.ci.outputs.is_master_sync }} + DOCS_ONLY: ${{ needs.ci.outputs.docs_only }} + CI_RESULT: ${{ needs.ci.result }} + run: | + echo "ci.result=$CI_RESULT docs_only=$DOCS_ONLY is_master_sync=$IS_MASTER_SYNC" + # next/hotfixes was force-synced to master — head SHA matches the + # default branch, nothing new to test, green-light without running CI. + if [ "$IS_MASTER_SYNC" = "true" ]; then + echo "Branch tip matches master — Required PR Check passes without running CI." + exit 0 + fi + # Docs-only PR — the reusable skipped the heavy chain and exported + # docs_only=true. Green-light Required PR Check so the ruleset + # doesn't block a docs change. + if [ "$DOCS_ONLY" = "true" ]; then + echo "Docs-only change — Required PR Check passes without running CI." + exit 0 + fi + if [ "$CI_RESULT" = "success" ]; then + echo "Reusable CI passed." + exit 0 + elif [ "$CI_RESULT" = "failure" ] || [ "$CI_RESULT" = "cancelled" ]; then + echo "Reusable CI did not pass." + exit 1 + else + # covers 'skipped' or undefined; force red to avoid silent green + echo "Reusable CI produced no pass/fail; treating as failure." + exit 1 + fi diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml new file mode 100644 index 0000000..f01f3d8 --- /dev/null +++ b/.github/workflows/cla.yml @@ -0,0 +1,60 @@ +# +# @Project: @cldmv/sizeofvar +# @Filename: /.github/workflows/cla.yml +# @Date: 2026-07-19 00:00:00 -07:00 (1784523600) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/cla.yml +# +# Per-CLA-version signing with per-repo override support. Each commit author +# must either: +# - Be in the org (silent pass via /orgs/CLDMV/members lookup) +# - Be in the exempt-bots list +# - Already have a signature record at the active (scope, version) in the +# central ledger repo (default: CLDMV/.cla-signatures) +# - Reply on this PR with the exact required text +# +# Default vs. override scope: +# - DEFAULT (this repo has NO root-level CLA.md): the bot uses the org-wide +# CLA at cla-versions/v.md in the ledger. Signing once covers every +# CLDMV repo that uses the default until the major.minor is bumped. +# - OVERRIDE (this repo HAS a root-level CLA.md): the bot enforces the +# consumer-repo text and reads the version from its header. Signatures +# live under signatures//overrides///v/ and +# are scoped to this repo only. +# +# Required setup: +# - Bot App must have `Organization permissions → Members: read` for the +# org-member exemption. +# - Bot App must have `Repository contents: write` on the ledger repo. +# - Optional `CLDMV_CLA_BOT_APP_CLIENT_ID` / `CLDMV_CLA_BOT_APP_PRIVATE_KEY` +# org secrets override the general bot identity for CLA actions only. +name: 📜 CLA + +on: + pull_request_target: + types: [opened, synchronize, reopened, ready_for_review] + issue_comment: + types: [created] + +permissions: + contents: read + pull-requests: write + statuses: write + issues: write + +jobs: + cla: + uses: CLDMV/.github/.github/workflows/reusable-cla.yml@v4 + with: + cla_version: "1.0" + secrets: + BOT_APP_CLIENT_ID: ${{ secrets.CLDMV_BOT_APP_CLIENT_ID }} + BOT_APP_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_APP_PRIVATE_KEY }} + CLA_BOT_APP_CLIENT_ID: ${{ secrets.CLDMV_CLA_BOT_APP_CLIENT_ID }} + CLA_BOT_APP_PRIVATE_KEY: ${{ secrets.CLDMV_CLA_BOT_APP_PRIVATE_KEY }} + TAGGER_NAME: ${{ secrets.CLDMV_BOT_NAME }} + TAGGER_EMAIL: ${{ secrets.CLDMV_BOT_EMAIL }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..026884b --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,70 @@ +# +# @Project: @cldmv/sizeofvar +# @Filename: /.github/workflows/codeql.yml +# @Date: 2026-05-20 00:00:00 -07:00 (1779606000) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/codeql.yml +# +# REQUIRED REPO SETTING — CodeQL must be in "Advanced" mode for this workflow +# to upload SARIF. If the repo has CodeQL "Default setup" enabled (the +# GitHub-managed alternative), upload runs fail with: +# +# "Code Scanning could not process the submitted SARIF file: CodeQL +# analyses from advanced configurations cannot be processed when the +# default setup is enabled" +# +# The org-bootstrap-repo action automatically disables default setup +# (overwrite-with-warn) on every fanout run, so a freshly-bootstrapped +# repo lands in the right state by default. If you want to KEEP default +# setup (the GitHub-managed config) instead of this workflow, DELETE +# this codeql.yml file — with the conflict gone, the bootstrap leaves +# default setup alone on subsequent runs. +# +# Manual fix when running outside the bootstrap: +# Settings → Code security and analysis → Code scanning → CodeQL +# analysis → ⚙️ → Switch to advanced. +name: 🔍 CodeQL + +on: + push: + branches: [master, main] + # Same fork-PR consideration as ci.yml: pull_request fires for forks; SARIF + # upload to base-repo Security tab fails with read-only token. Acceptable — + # push-to-master analysis after merge catches anything missed. DO NOT use + # pull_request_target (runs base-repo workflow with secrets against fork + # code; dangerous). + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + # Include the v4 integration branches (`next`, `hotfixes`) so feature + # and hotfix PRs trigger CodeQL. Without these, branch protection + # rulesets that require the CodeQL check on `next`/`hotfixes` will + # sit on "waiting for results" indefinitely. Branches that don't + # exist in a given repo simply never trigger the workflow — harmless + # for repos that haven't adopted the v4 staging-branch flow. + branches: [master, main, next, hotfixes] + schedule: + - cron: "37 14 * * 1" # weekly Monday 14:37 UTC; GitHub updates queries over time + +permissions: + security-events: write + contents: read + actions: read + +concurrency: + group: codeql-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/master' && github.ref != 'refs/heads/main' }} + +jobs: + analyze: + uses: CLDMV/.github/.github/workflows/reusable-codeql.yml@v4 + with: + languages: "javascript-typescript" + # Override defaults if needed: + # queries: "security-extended,security-and-quality" + # paths_ignore: "node_modules/,dist/,coverage/,**/test/**" + # config_file: ".github/codeql-config.yml" + # build_mode: "autobuild" diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml new file mode 100644 index 0000000..61abd9f --- /dev/null +++ b/.github/workflows/dependabot-auto-merge.yml @@ -0,0 +1,54 @@ +# +# @Project: @cldmv/sizeofvar +# @Filename: /.github/workflows/dependabot-auto-merge.yml +# @Date: 2026-05-20 00:00:00 -07:00 (1779606000) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/dependabot-auto-merge.yml +# +# Auto-approves + queues auto-merge for Dependabot patch/minor bumps after +# CI passes. Major bumps are left for a human. +# +# Default in v4: ON. To opt out, delete this file — Dependabot PRs still +# flow into `next` (via dependabot.yml) but require a manual merge click. +# +# How v4 routing works: +# - dependabot.yml sets `target-branch: next`, so Dependabot opens PRs +# against `next`. This workflow auto-merges those PRs into `next` after +# CI; they batch into the next release like every other change. +# - For security advisories, hotfix-redirector.yml (release-flow-v4/) +# detects GHSA references in the PR body and retargets the PR from +# `next` → `hotfixes` *before* this workflow runs, so security updates +# auto-merge into the hotfix lane instead of waiting for the next batch. +# +# Required setup (one-time per repo): +# 1. Settings → Pull Requests → "Allow auto-merge" → ON +# (enabled automatically by `release-flow-v4/v4-bootstrap.yml`) +# 2. Branch protection on `next` and `hotfixes` with required CI status +# checks — the action refuses to merge into an unprotected branch. +# Both are validated by the action; the workflow fails loudly if missing. +name: 🤖 Dependabot Auto-Merge + +on: + pull_request: + types: [opened, reopened, synchronize, ready_for_review] + +permissions: + contents: write + pull-requests: write + +jobs: + automerge: + # Pre-filter at workflow level so this doesn't spin up for every PR. + if: github.event.pull_request.user.login == 'dependabot[bot]' + uses: CLDMV/.github/.github/workflows/reusable-dependabot-auto-merge.yml@v4 + with: + bump_types: "patch,minor" + merge_method: "squash" + # also_for_actors: "renovate[bot]" # extend if you adopt Renovate + secrets: + BOT_APP_CLIENT_ID: ${{ secrets.CLDMV_BOT_APP_CLIENT_ID }} + BOT_APP_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_APP_PRIVATE_KEY }} diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000..a6bda50 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,34 @@ +# +# @Project: @cldmv/sizeofvar +# @Filename: /.github/workflows/dependency-review.yml +# @Date: 2026-05-20 00:00:00 -07:00 (1779606000) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/dependency-review.yml +name: 🔒 Dependency Review + +on: + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + branches: [master, main] + +permissions: + contents: read + pull-requests: write + +jobs: + review: + uses: CLDMV/.github/.github/workflows/reusable-dependency-review.yml@v4 + with: + fail_on_severity: "moderate" + # Per-repo license policy override: + # deny_licenses: "AGPL-3.0,LGPL-3.0" # block copyleft for an Apache-2.0 repo + # Bot App credentials. When set, the dependency-review PR comment is + # posted by the consumer's bot App instead of github-actions[bot]. + # Both lines are optional; remove them to fall back to GITHUB_TOKEN. + secrets: + BOT_APP_CLIENT_ID: ${{ secrets.CLDMV_BOT_APP_CLIENT_ID }} + BOT_APP_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_APP_PRIVATE_KEY }} diff --git a/.github/workflows/feature-pr.yml b/.github/workflows/feature-pr.yml new file mode 100644 index 0000000..fcee49e --- /dev/null +++ b/.github/workflows/feature-pr.yml @@ -0,0 +1,59 @@ +# +# @Project: @cldmv/.github +# @Filename: /examples/individual-repo-workflows/release-flow-v4/feature-pr.yml +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/feature-pr.yml +# +# v4 ergonomics: auto-opens (and refreshes) a PR from a code-side branch to the +# right integration branch on every push. +# +# Mapping (matches CLDMV/.github docs/conventions/branch-naming.md): +# feat/*, feature/*, fix/*, release/*, chore/*, refactor/*, +# docs/*, ci/*, perf/*, test/*, style/* → next +# hotfix/* → hotfixes +# +# Reserved branches NOT auto-PR'd: dependabot/* and copilot/* (they manage their +# own PRs); badges, gh-pages (bot-only); master/main (the target). +# +# Thin caller: all job logic (target detection, changelog body, PR create/ +# refresh) lives in the reusable, pinned at @v4. Bumping the pin carries fixes +# without editing this file. The `push` trigger and its branch-prefix list stay +# here (GitHub requires the trigger local, and the list is per-repo config). +name: 🔀 Feature PR (v4) + +on: + push: + branches: + # CUSTOMIZE: prune this list to whichever branch prefixes your + # repo uses. Must align with the `case` statement in the reusable. + - 'feat/**' + - 'feature/**' + - 'fix/**' + - 'release/**' + - 'chore/**' + - 'refactor/**' + - 'docs/**' + - 'ci/**' + - 'perf/**' + - 'test/**' + - 'style/**' + - 'hotfix/**' + +concurrency: + group: feature-pr-${{ github.repository }}-${{ github.ref }} + cancel-in-progress: false + +jobs: + open-pr: + permissions: + contents: read + pull-requests: write + uses: CLDMV/.github/.github/workflows/workflow-feature-pr.yml@v4 + secrets: + # Map your repo/org secrets to the expected names. + BOT_APP_CLIENT_ID: ${{ secrets.CLDMV_BOT_APP_CLIENT_ID }} + BOT_APP_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_APP_PRIVATE_KEY }} diff --git a/.github/workflows/hotfix-redirector.yml b/.github/workflows/hotfix-redirector.yml new file mode 100644 index 0000000..830cad6 --- /dev/null +++ b/.github/workflows/hotfix-redirector.yml @@ -0,0 +1,51 @@ +# +# @Project: @cldmv/.github +# @Filename: /examples/individual-repo-workflows/release-flow-v4/hotfix-redirector.yml +# @Date: 2026-05-22 00:00:00 -07:00 (1779778800) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/hotfix-redirector.yml +# +# v4 hotfix lane: retarget hotfix/security PRs to the `hotfixes` branch. +# +# Two paths trigger a redirect (CLDMV/.github docs/conventions/release-flow-v4.md §5.2, §6.5): +# 1. Head branch matches `hotfix/*` or `security/*` (human-driven hotfix flow). +# 2. Author is `dependabot[bot]` AND its base isn't Dependabot's routine +# target-branch (default "next") — GitHub always overrides dependabot.yml's +# target-branch for security updates, so a base landing on the default +# branch instead of "next" is itself the signal. Routine version bumps stay +# on "next". +# +# Thin caller: all job logic (token, checkout, git identity, redirect action) +# lives in the reusable, pinned at @v4. Bumping the pin carries new requirements +# (e.g. the checkout + git identity the cherry-pick path needs) without editing +# this file. +name: 🔀 Hotfix PR Redirector (v4) + +# SECURITY NOTE: pull_request_target runs in the BASE repo's context with WRITE +# permissions + secrets. The reusable checks out `hotfixes` (a trusted base-repo +# branch, NOT the PR head/fork) and only cherry-picks/pushes against it. +# +# `opened` only (NOT `edited`): if a maintainer manually re-targets the PR, we +# must not fight them by redirecting again. +on: + pull_request_target: + types: [opened] + +concurrency: + group: hotfix-redirector-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + redirect: + permissions: + contents: write + pull-requests: write + uses: CLDMV/.github/.github/workflows/workflow-hotfix-redirector.yml@v4 + secrets: + # Map your repo/org secrets to the expected names. + BOT_APP_CLIENT_ID: ${{ secrets.CLDMV_BOT_APP_CLIENT_ID }} + BOT_APP_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_APP_PRIVATE_KEY }} diff --git a/.github/workflows/hotfixes-release.yml b/.github/workflows/hotfixes-release.yml new file mode 100644 index 0000000..6e3b3b8 --- /dev/null +++ b/.github/workflows/hotfixes-release.yml @@ -0,0 +1,55 @@ +# +# @Project: @cldmv/.github +# @Filename: /examples/individual-repo-workflows/release-flow-v4/hotfixes-release.yml +# @Date: 2026-05-22 00:00:00 -07:00 (1779778800) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/hotfixes-release.yml +# +# v4 hotfix lane: maintain the ONE persistent `hotfixes → master` release PR. +# +# Mirror of next-release.yml but for the `hotfixes` integration branch +# (CLDMV/.github docs/conventions/release-flow-v4.md §5.4, §6.2). Fires on every +# push to `hotfixes` (hotfix/security PR squash-merges land here), and +# resolves-or-creates the persistent `hotfixes → master` release PR. +# +# Thin caller: all job logic (plan / create / refresh) lives in the reusable, +# pinned at @v4. Bumping the pin carries fixes without editing this file. +# CUSTOMIZE `package_name` / `build_command` to match your package (same values +# as your next-release.yml). +name: 🚑 Hotfixes Release (v4) + +on: + push: + branches: [hotfixes] + workflow_dispatch: # manual kick — e.g. to open/refresh the PR for content already on `hotfixes` + +concurrency: + group: hotfixes-release-${{ github.repository }} + cancel-in-progress: false + +jobs: + release: + permissions: + contents: write + pull-requests: write + uses: CLDMV/.github/.github/workflows/workflow-hotfixes-release.yml@v4 + with: + package_name: "@cldmv/sizeofvar" + build_command: "echo '✓ no build step'" + secrets: + # Map your repo/org secrets to the expected names. + BOT_APP_CLIENT_ID: ${{ secrets.CLDMV_BOT_APP_CLIENT_ID }} + BOT_APP_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_APP_PRIVATE_KEY }} + # Optional release-PR notifier webhooks — each is independently + # opt-in: leave one unset and that channel is silently skipped. + # Delete the lines you don't use. + DISCORD_RELEASE_PR_PUBLIC_WEBHOOK: ${{ secrets.DISCORD_RELEASE_PR_PUBLIC_WEBHOOK }} + DISCORD_RELEASE_PR_PRIVATE_WEBHOOK: ${{ secrets.DISCORD_RELEASE_PR_PRIVATE_WEBHOOK }} + SLACK_RELEASE_PR_PUBLIC_WEBHOOK: ${{ secrets.SLACK_RELEASE_PR_PUBLIC_WEBHOOK }} + SLACK_RELEASE_PR_PRIVATE_WEBHOOK: ${{ secrets.SLACK_RELEASE_PR_PRIVATE_WEBHOOK }} + GENERIC_RELEASE_PR_PUBLIC_WEBHOOK: ${{ secrets.GENERIC_RELEASE_PR_PUBLIC_WEBHOOK }} + GENERIC_RELEASE_PR_PRIVATE_WEBHOOK: ${{ secrets.GENERIC_RELEASE_PR_PRIVATE_WEBHOOK }} diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 0000000..480adaa --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,44 @@ +# +# @Project: @cldmv/sizeofvar +# @Filename: /.github/workflows/labeler.yml +# @Date: 2026-05-20 00:00:00 -07:00 (1779606000) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/labeler.yml +# +# Path-based PR auto-labeler. Uses CLDMV's org-default labeler.default.yml; +# override per-repo by adding .github/labeler.yml in this repo (same shape). +# +# Labels applied additively — never removes labels added by humans or other +# automation. +# +# Batch 5.2 from tmp/plan-future-workflows.md. +name: 🏷️ PR Labeler + +# SECURITY NOTE: This workflow uses pull_request_target so it can apply labels +# to fork PRs. pull_request_target runs in the BASE repo's context with WRITE +# permissions and access to secrets. This is SAFE for THIS workflow because: +# - We never checkout the PR head ref +# - We never run code from the PR (no `run:` step uses PR data) +# - We only call REST APIs to read the file list and post labels +# DO NOT add a checkout step or any step that executes PR-supplied content +# (build commands, scripts, test runs, etc.) to this workflow. +on: + pull_request_target: + types: [opened, synchronize, reopened, ready_for_review] + +permissions: + contents: read + pull-requests: write + +jobs: + label: + uses: CLDMV/.github/.github/workflows/reusable-pr-labeler.yml@v4 + # Optional. Without these, labels are attributed to github-actions[bot]. + # With these, they're attributed to your CLDMV bot App. + secrets: + BOT_APP_CLIENT_ID: ${{ secrets.CLDMV_BOT_APP_CLIENT_ID }} + BOT_APP_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_APP_PRIVATE_KEY }} diff --git a/.github/workflows/master-commit-audit.yml b/.github/workflows/master-commit-audit.yml new file mode 100644 index 0000000..f853d1d --- /dev/null +++ b/.github/workflows/master-commit-audit.yml @@ -0,0 +1,66 @@ +# +# @Project: @cldmv/sizeofvar +# @Filename: /.github/workflows/master-commit-audit.yml +# @Date: 2026-05-20 00:00:00 -07:00 (1779606000) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/master-commit-audit.yml +# +# Post-merge safety net: when any commit lands on the default branch, verify +# its subject matches the expected release-flow patterns. On miss, auto-file +# a GitHub Issue (deduped by SHA) so the alert is persistent and assignable +# — not just a red ❌ that dies in inbox. +# +# Catches: release-workflow title-generation regressions, branch-protection +# bypasses, unexpected bot commits, direct emergency pushes. +# +# Batch 5.1 from tmp/plan-future-workflows.md. +name: 🧾 Master Commit Audit + +on: + push: + branches: [master, main] + +permissions: + contents: read + issues: write + +jobs: + audit: + runs-on: ubuntu-latest + steps: + # Optional. Without these, the audit issue is filed by + # github-actions[bot]. With them, the issue is filed by your bot App. + - name: Create App token (falls back to GITHUB_TOKEN) + id: app-token + uses: CLDMV/.github/.github/actions/github/steps/create-app-token@v4 + with: + client_id: ${{ secrets.CLDMV_BOT_APP_CLIENT_ID }} + private_key: ${{ secrets.CLDMV_BOT_APP_PRIVATE_KEY }} + env: + BOT_APP_CLIENT_ID: ${{ secrets.CLDMV_BOT_APP_CLIENT_ID }} + BOT_APP_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_APP_PRIVATE_KEY }} + + - name: Audit commit subject + uses: CLDMV/.github/.github/actions/git/jobs/audit-commit-subject@v4 + with: + commit_sha: ${{ github.sha }} + # allowed_patterns omitted -> inherit the canonical default from + # audit-commit-subject (release/chore/merge patterns, including + # the "release: vX.Y.Z - " form). Customize only if + # this repo's conventions genuinely differ — a hardcoded copy + # here goes stale the next time the canonical default changes. + # allowed_patterns: | + # ^release: v\d+\.\d+\.\d+( - .+?)?( \(#\d+\))?$ + # ^chore(\([^)]+\))?: .+ + # ^Merge pull request #\d+ from .+ + # ^feat(\([^)]+\))?: .+ + # Canonical label names from CLDMV/.github's data/github-labels.json + # (note the space after each colon). Replace with names that exist + # in your repo's label catalog. + issue_labels: "type: ci,priority: high" + # issue_assignee: "shinrai" # uncomment to auto-assign + github_token: ${{ steps.app-token.outputs.token }} diff --git a/.github/workflows/next-release.yml b/.github/workflows/next-release.yml new file mode 100644 index 0000000..f4df762 --- /dev/null +++ b/.github/workflows/next-release.yml @@ -0,0 +1,61 @@ +# +# @Project: @cldmv/.github +# @Filename: /examples/individual-repo-workflows/release-flow-v4/next-release.yml +# @Date: 2026-05-22 00:00:00 -07:00 (1779778800) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/next-release.yml +# +# v4 core: maintain the ONE persistent `next → master` release PR for this repo. +# +# Fires on every push to `next` (contributor PR squash-merges land here). +# Resolves the existing release PR and refreshes it, or creates it the first +# time `next` diverges from master. The release PR batches all accumulated +# feature commits into a single release — that batching is v4's whole point +# (see CLDMV/.github docs/conventions/release-flow-v4.md §5.3, §6.1). +# +# Thin caller: all job logic (plan / create / refresh) lives in the reusable, +# pinned at @v4. Bumping the pin carries fixes without editing this file. +# CUSTOMIZE: +# - `package_name` → your npm package (or any unique identifier) +# - `build_command` → your build script, or a stub like +# `echo '✓ no build step'` for a meta package (optional; +# defaults to `npm run build:ci`) +name: 🚀 Next Release (v4) + +on: + push: + branches: [next] + workflow_dispatch: # manual kick — e.g. to open/refresh the PR for content already on `next` + +# Serialize: each run re-resolves the current PR state, so queueing (not +# cancelling) avoids a create/refresh race when pushes land back-to-back. +concurrency: + group: next-release-${{ github.repository }} + cancel-in-progress: false + +jobs: + release: + permissions: + contents: write + pull-requests: write + uses: CLDMV/.github/.github/workflows/workflow-next-release.yml@v4 + with: + package_name: "@cldmv/sizeofvar" + build_command: "echo '✓ no build step'" + secrets: + # Map your repo/org secrets to the expected names. + BOT_APP_CLIENT_ID: ${{ secrets.CLDMV_BOT_APP_CLIENT_ID }} + BOT_APP_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_APP_PRIVATE_KEY }} + # Optional release-PR notifier webhooks — each is independently + # opt-in: leave one unset and that channel is silently skipped. + # Delete the lines you don't use. + DISCORD_RELEASE_PR_PUBLIC_WEBHOOK: ${{ secrets.DISCORD_RELEASE_PR_PUBLIC_WEBHOOK }} + DISCORD_RELEASE_PR_PRIVATE_WEBHOOK: ${{ secrets.DISCORD_RELEASE_PR_PRIVATE_WEBHOOK }} + SLACK_RELEASE_PR_PUBLIC_WEBHOOK: ${{ secrets.SLACK_RELEASE_PR_PUBLIC_WEBHOOK }} + SLACK_RELEASE_PR_PRIVATE_WEBHOOK: ${{ secrets.SLACK_RELEASE_PR_PRIVATE_WEBHOOK }} + GENERIC_RELEASE_PR_PUBLIC_WEBHOOK: ${{ secrets.GENERIC_RELEASE_PR_PUBLIC_WEBHOOK }} + GENERIC_RELEASE_PR_PRIVATE_WEBHOOK: ${{ secrets.GENERIC_RELEASE_PR_PRIVATE_WEBHOOK }} diff --git a/.github/workflows/next-reset.yml b/.github/workflows/next-reset.yml new file mode 100644 index 0000000..87ba088 --- /dev/null +++ b/.github/workflows/next-reset.yml @@ -0,0 +1,43 @@ +# +# @Project: @cldmv/.github +# @Filename: /examples/individual-repo-workflows/release-flow-v4/next-reset.yml +# @Date: 2026-05-22 00:00:00 -07:00 (1779778800) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/next-reset.yml +# +# v4 core: after a release lands on master, re-sync the integration branches +# (CLDMV/.github docs/conventions/release-flow-v4.md §6.3, §7). +# +# - `hotfixes` is ALWAYS force-reset to master HEAD after any release. +# - `next` depends on which lane released: +# * normal release (next → master, or a v3-style feat → master): +# force-reset `next` to master HEAD (§7.1). +# * hotfix release (hotfixes → master): MERGE master into `next` instead, +# so next's accumulated feature work is preserved (§7.2, option B). +# +# Thin caller: all job logic (the wait-for-tags gate + the branch sync) lives in +# the reusable, pinned at @v4. Bumping the pin carries fixes without editing +# this file. +name: ♻️ Next/Hotfixes Reset (v4) + +on: + push: + branches: [master, main] + +concurrency: + group: next-reset-${{ github.repository }} + cancel-in-progress: false + +jobs: + sync: + permissions: + contents: write + uses: CLDMV/.github/.github/workflows/workflow-next-reset.yml@v4 + secrets: + # Map your repo/org secrets to the expected names. + BOT_APP_CLIENT_ID: ${{ secrets.CLDMV_BOT_APP_CLIENT_ID }} + BOT_APP_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_APP_PRIVATE_KEY }} diff --git a/.github/workflows/pr-title-normalizer.yml b/.github/workflows/pr-title-normalizer.yml new file mode 100644 index 0000000..adba973 --- /dev/null +++ b/.github/workflows/pr-title-normalizer.yml @@ -0,0 +1,45 @@ +# +# @Project: @cldmv/.github +# @Filename: /examples/individual-repo-workflows/release-flow-v4/pr-title-normalizer.yml +# @Date: 2026-05-22 00:00:00 -07:00 (1779778800) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/pr-title-normalizer.yml +# +# Normalize contributor PR titles to Conventional Commits format, derived from +# the highest-priority commit in the PR. The release flow expects this shape, so +# a v4 repo wants this enabled. (Also backportable to v3 repos — the underlying +# action shipped in v3.3.0; it owns all skip logic: bot authors, the +# long-running release PRs, titles already starting with `release:`, and titles +# that already conform.) +# +# Thin caller: all job logic lives in the reusable, pinned at @v4. Bumping the +# pin carries fixes without editing this file. +name: 🏷️ PR Title Normalizer + +# SECURITY NOTE: pull_request_target runs in the BASE repo's context with WRITE +# permissions and access to secrets. SAFE — the reusable's path is API-only (it +# never checks out or executes PR content). Triggers on opened + synchronize +# only (NOT edited): a maintainer hand-editing the title must not kick off a +# re-normalize loop. +on: + pull_request_target: + types: [opened, synchronize] + +concurrency: + group: pr-title-normalizer-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + normalize: + permissions: + contents: read + pull-requests: write + uses: CLDMV/.github/.github/workflows/workflow-pr-title-normalizer.yml@v4 + secrets: + # Map your repo/org secrets to the expected names. + BOT_APP_CLIENT_ID: ${{ secrets.CLDMV_BOT_APP_CLIENT_ID }} + BOT_APP_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_APP_PRIVATE_KEY }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..6236490 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,125 @@ +# +# @Project: @cldmv/sizeofvar +# @Filename: /.github/workflows/publish.yml +# @Date: 2026-05-20 00:00:00 -07:00 (1779606000) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/publish.yml +name: 📦 Release and Publish + +on: + push: + branches: [master, main] + paths-ignore: + - "**.md" + - ".github/ISSUE_TEMPLATE/**" + - ".github/PULL_REQUEST_TEMPLATE/**" + workflow_dispatch: + inputs: + debug: + description: "Enable debug logging for troubleshooting" + type: boolean + required: false + default: false + dry_run: + description: "Dry run mode - validate everything but don't publish or create releases" + type: boolean + required: false + default: false + node_version: + description: "Node.js version to use (default: lts/*)" + type: string + required: false + default: "lts/*" + package_manager: + description: "Package manager (npm or yarn)" + type: string + required: false + default: "npm" + test_environment: + description: "Environment for tests (affects NODE_ENV and NODE_OPTIONS --conditions flag)" + type: string + required: false + default: "development" + version: + description: "Version to publish (auto-detected from package.json if not provided)" + type: string + required: false + default: "" + publish_to_npm: + description: "Publish to NPM registry" + type: boolean + required: false + default: true + publish_to_github_packages: + description: "Publish to GitHub Packages registry" + type: boolean + required: false + default: true + min_node_version: + description: "Minimum Node.js version for matrix testing (enables matrix when set)" + type: string + required: false + default: "20" + max_node_major: + description: "Override max Node.js major version (default: 22)" + type: string + required: false + default: "22" + use_gpg: + description: "Enable GPG signing (if GPG secrets provided)" + type: boolean + required: false + default: false + +# NEVER cancel an in-flight publish — half-published versions are nasty to +# clean up. Concurrent publishes for the same ref queue instead so they +# serialize naturally. +concurrency: + group: publish-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + +jobs: + publish-package: + if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' + permissions: + contents: write + packages: write + id-token: write + uses: CLDMV/.github/.github/workflows/workflow-publish.yml@v4 + with: + package_name: "@cldmv/sizeofvar" # Required: replace with your NPM package name + debug: ${{ github.event.inputs.debug == 'true' }} + dry_run: ${{ github.event.inputs.dry_run == 'true' }} + node_version: ${{ github.event.inputs.node_version || 'lts/*' }} + package_manager: ${{ github.event.inputs.package_manager || 'npm' }} + version: ${{ github.event.inputs.version || '' }} + publish_to_npm: ${{ github.event.inputs.publish_to_npm != 'false' }} + publish_to_github_packages: ${{ github.event.inputs.publish_to_github_packages != 'false' }} + publish_command: "" + github_packages_publish_command: "" + min_node_version: ${{ github.event.inputs.min_node_version || '20' }} + max_node_major: ${{ github.event.inputs.max_node_major || '22' }} + test_command: "npm test" # Use defaults: NODE_ENV=development, NODE_OPTIONS=--conditions=development + # test_command: "NODE_OPTIONS='--conditions=slothlet-dev' npm test" # Override NODE_OPTIONS only + # test_command: "NODE_ENV=test npm test" # Override NODE_ENV only + # test_command: "NODE_ENV=test NODE_OPTIONS='--conditions=slothlet-dev' npm test" # Override both + test_environment: ${{ github.event.inputs.test_environment || 'development' }} # Alternative to setting in test_command + build_command: "npm run build:ci" + is_prerelease: false + release_source_only: false + create_documentation: true + skip_performance_tests: false + skip_matrix_tests: false + use_gpg: ${{ github.event.inputs.use_gpg == 'true' }} + secrets: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + BOT_APP_CLIENT_ID: ${{ secrets.CLDMV_BOT_APP_CLIENT_ID }} + BOT_APP_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_APP_PRIVATE_KEY }} + TAGGER_NAME: ${{ secrets.CLDMV_BOT_NAME }} + TAGGER_EMAIL: ${{ secrets.CLDMV_BOT_EMAIL }} + GPG_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_GPG_PRIVATE_KEY }} + GPG_PASSPHRASE: ${{ secrets.CLDMV_BOT_GPG_PASSPHRASE }} diff --git a/.github/workflows/release-notify.yml b/.github/workflows/release-notify.yml new file mode 100644 index 0000000..24e572b --- /dev/null +++ b/.github/workflows/release-notify.yml @@ -0,0 +1,37 @@ +# +# @Project: @cldmv/sizeofvar +# @Filename: /.github/workflows/release-notify.yml +# @Date: 2026-07-19 00:00:00 -07:00 (1784523600) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/release-notify.yml +# +# Fires on `release: published` and dispatches the release announcement to +# any enabled webhook. No config file — each channel is just a secret: +# +# DISCORD_RELEASES_PUBLIC_WEBHOOK / DISCORD_RELEASES_PRIVATE_WEBHOOK +# SLACK_RELEASES_PUBLIC_WEBHOOK / SLACK_RELEASES_PRIVATE_WEBHOOK +# GENERIC_RELEASES_PUBLIC_WEBHOOK / GENERIC_RELEASES_PRIVATE_WEBHOOK +# +# Visibility is determined automatically from the repo: GitHub `public` → +# PUBLIC, `private` or `internal` → PRIVATE. Set the org-level secret in +# CLDMV for the default URL; set a repo-level secret with the same name to +# override (or to an empty string to mute that channel for this repo). +name: 📣 Release Notify + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + notify: + # Defensive: skip untagged releases (mirrors Batch 1.2's filter) + if: github.event.release.tag_name != '' + uses: CLDMV/.github/.github/workflows/reusable-release-notifier.yml@v4 + secrets: inherit diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 0000000..3b36925 --- /dev/null +++ b/.github/workflows/scorecard.yml @@ -0,0 +1,61 @@ +# +# @Project: @cldmv/sizeofvar +# @Filename: /.github/workflows/scorecard.yml +# @Date: 2026-07-19 00:00:00 -07:00 (1784523600) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/scorecard.yml +# +# OpenSSF Scorecard — scans the repo against ~18 security best-practice checks +# and produces a 0-10 score. Thin caller: the steps and the SHA-pinned +# scorecard-action version live in reusable-scorecard.yml@v4, so the action +# version can't drift in this copy (it just calls the org reusable). Triggers +# stay here, per OpenSSF's recommended setup. +# +# NOTE: this MUST stay a thin caller. OSSF Scorecard's publish step verifies +# the analysis job and allows only a fixed set of steps; the inline form used +# our checkout-code composite, which trips "job has unallowed step" -> publish +# HTTP 400. The reusable uses actions/checkout directly, which passes. +name: 🔬 OpenSSF Scorecard + +on: + branch_protection_rule: + schedule: + - cron: "32 7 * * 1" # weekly Monday 07:32 UTC + push: + branches: [master, main] + workflow_dispatch: + +# Caller must grant what the reusable needs — notably id-token: write for the +# OpenSSF transparency-log publish. +# +# No workflow-level `permissions:` here — grant on the `analyze` job below +# instead. scorecard-action's publish step verifies that write permissions +# were granted JOB-scoped, not workflow-wide (matching OSSF's own example: +# https://github.com/ossf/scorecard-action#example-workflow). A workflow-level +# grant satisfies GitHub's own reusable-workflow permission rules fine, but +# still trips scorecard-action's own check — the rejection ("workflow +# verification failed: global perm is set to write: permission for X is set +# to write") means "granted globally," not "forbidden." +# +# Do NOT add security-events: write here while publish_results: true below. +# scorecard-action's publish step rejects submissions from a workflow whose +# token has security-events write access (it verifies the caller can't have +# tampered with results before they hit the public transparency log). That +# trade-off means the reusable's own SARIF-to-Security-tab upload step has no +# permission to run in this configuration; the public OpenSSF badge is the +# thing actually enabled here, so this repo takes that trade-off. Only add +# security-events: write back (job-scoped) if publish_results is set to false +# instead. +jobs: + analyze: + permissions: + id-token: write + contents: read + actions: read + uses: CLDMV/.github/.github/workflows/reusable-scorecard.yml@v4 + with: + publish_results: true # set false for private repos / to skip the public badge diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..9d9763e --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,46 @@ +# +# @Project: @cldmv/sizeofvar +# @Filename: /.github/workflows/stale.yml +# @Date: 2026-05-20 00:00:00 -07:00 (1779606000) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/stale.yml +# +# First-run guidance: on a repo with an existing backlog, the first +# scheduled run can mark a LOT of issues stale at once (notification storm). +# Recommended: enable with `dry_run: true` first, dispatch manually to +# preview, then flip to live. The dispatch input below makes this easy. +# +# Batch 2.3 from tmp/plan-future-workflows.md. +name: 🍂 Stale Issues & PRs + +on: + schedule: + - cron: "13 5 * * *" # daily 05:13 UTC (off-the-hour to avoid GH cron stampede) + workflow_dispatch: + inputs: + dry_run: + description: "Preview only — no changes will be made" + type: boolean + default: false + +permissions: + issues: write + pull-requests: write + +jobs: + sweep: + uses: CLDMV/.github/.github/workflows/reusable-stale.yml@v4 + with: + dry_run: ${{ github.event.inputs.dry_run == 'true' }} + # Override timers if needed: + # days_before_issue_stale: 60 + # days_before_issue_close: 14 + # days_before_pr_stale: 30 + # days_before_pr_close: 7 + secrets: + BOT_APP_CLIENT_ID: ${{ secrets.CLDMV_BOT_APP_CLIENT_ID }} + BOT_APP_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_APP_PRIVATE_KEY }} diff --git a/.github/workflows/tag-health.yml b/.github/workflows/tag-health.yml new file mode 100644 index 0000000..6539b1d --- /dev/null +++ b/.github/workflows/tag-health.yml @@ -0,0 +1,64 @@ +# +# @Project: @cldmv/sizeofvar +# @Filename: /.github/workflows/tag-health.yml +# @Date: 2026-05-20 00:00:00 -07:00 (1779606000) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/tag-health.yml +# +# Wakes the reusable-tag-health.yml workflow on a weekly schedule. The +# reusable already implements validation, bot-signature fixes, unsigned-tag +# fixes, orphaned-release recovery, orphaned-tag relocation, and rolling +# major/minor tag maintenance — but it's dormant by default. This template +# is what triggers it. +# +# Batch 3.1 from tmp/plan-future-workflows.md. +name: 🏥 Tag Health + +on: + schedule: + # Weekly Sunday 04:04 UTC. Off-the-hour to dodge the GitHub :00-cron + # stampede; weekly cadence because tag drift accumulates slowly. + - cron: "4 4 * * 0" + workflow_dispatch: + inputs: + debug: + description: "Enable debug logging for troubleshooting" + type: boolean + required: false + default: false + create_documentation: + description: "Update VERSION_TAGS.md if rolling tags moved" + type: boolean + required: false + default: false + use_gpg: + description: "Enable GPG signing for any tags the sweep creates/recreates" + type: boolean + required: false + default: true + +permissions: + contents: write + +jobs: + health: + uses: CLDMV/.github/.github/workflows/reusable-tag-health.yml@v4 + with: + debug: ${{ github.event.inputs.debug == 'true' }} + # Full unified sweep: validates, fixes bot signatures, fixes + # unsigned tags, recovers orphaned releases, relocates orphaned + # tags, and updates rolling major/minor refs. + run_unified_tag_health: true + create_documentation: ${{ github.event.inputs.create_documentation == 'true' }} + use_gpg: ${{ github.event.inputs.use_gpg != 'false' }} + secrets: + BOT_APP_CLIENT_ID: ${{ secrets.CLDMV_BOT_APP_CLIENT_ID }} + BOT_APP_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_APP_PRIVATE_KEY }} + TAGGER_NAME: ${{ secrets.CLDMV_BOT_NAME }} + TAGGER_EMAIL: ${{ secrets.CLDMV_BOT_EMAIL }} + GPG_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_GPG_PRIVATE_KEY }} + GPG_PASSPHRASE: ${{ secrets.CLDMV_BOT_GPG_PASSPHRASE }} diff --git a/.github/workflows/update-major-version-tags.yml b/.github/workflows/update-major-version-tags.yml new file mode 100644 index 0000000..b0e8145 --- /dev/null +++ b/.github/workflows/update-major-version-tags.yml @@ -0,0 +1,87 @@ +# +# @Project: @cldmv/sizeofvar +# @Filename: /.github/workflows/update-major-version-tags.yml +# @Date: 2026-05-20 00:00:00 -07:00 (1779606000) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/update-major-version-tags.yml +name: 🏷️ Update Major Version Tags + +on: + release: + types: [published] + workflow_dispatch: + inputs: + debug: + description: "Enable debug logging for troubleshooting" + type: boolean + required: false + default: false + create_documentation: + description: "Whether to create/update VERSION_TAGS.md documentation" + type: boolean + required: false + default: false + use_gpg: + description: "Enable GPG signing (if GPG secrets provided)" + type: boolean + required: false + default: true + # Tag health configuration + max_tags: + description: "Maximum number of tags to process (safety limit)" + required: false + default: "100" + max_major_versions: + description: "Maximum number of major versions to process" + required: false + default: "10" + max_minor_versions: + description: "Maximum number of minor versions per major to process" + required: false + default: "10" + bot_patterns: + description: "JSON array of bot name patterns to identify bot signatures" + required: false + default: '["CLDMV Bot", "cldmv-bot", "github-actions[bot]"]' + include_patterns: + description: "JSON array of tag patterns to include (e.g. ['v*', 'release-*'])" + required: false + default: '["v*"]' + exclude_patterns: + description: "JSON array of tag patterns to exclude" + required: false + default: "[]" + +jobs: + update-tags: + # Skip release events fired without a tag_name (e.g. "untagged-" runs + # the bot or a prior code path can produce). The reusable workflow has its + # own tag-readiness polling for forward-facing prevention; this guard + # protects against legacy / external sources of untagged release events. + # Batch 1.2 from tmp/plan-future-workflows.md. + if: github.event_name != 'release' || github.event.release.tag_name != '' + uses: CLDMV/.github/.github/workflows/workflow-update-major-version-tags.yml@v4 + permissions: + contents: write + with: + debug: ${{ github.event.inputs.debug == 'true' }} + create_documentation: ${{ github.event.inputs.create_documentation == 'true' }} + use_gpg: ${{ github.event.inputs.use_gpg != 'false' }} + max_tags: ${{ github.event.inputs.max_tags || '100' }} + max_major_versions: ${{ github.event.inputs.max_major_versions || '10' }} + max_minor_versions: ${{ github.event.inputs.max_minor_versions || '10' }} + bot_patterns: ${{ github.event.inputs.bot_patterns || '["CLDMV Bot", "cldmv-bot", "github-actions[bot]"]' }} + include_patterns: ${{ github.event.inputs.include_patterns || '["v*"]' }} + exclude_patterns: ${{ github.event.inputs.exclude_patterns || '[]' }} + secrets: + # Map your repo/org secrets to the expected names + TAGGER_NAME: ${{ secrets.CLDMV_BOT_NAME }} + TAGGER_EMAIL: ${{ secrets.CLDMV_BOT_EMAIL }} + GPG_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_GPG_PRIVATE_KEY }} + GPG_PASSPHRASE: ${{ secrets.CLDMV_BOT_GPG_PASSPHRASE }} + BOT_APP_CLIENT_ID: ${{ secrets.CLDMV_BOT_APP_CLIENT_ID }} + BOT_APP_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_APP_PRIVATE_KEY }} diff --git a/.github/workflows/v4-bootstrap.yml b/.github/workflows/v4-bootstrap.yml new file mode 100644 index 0000000..bc26f1b --- /dev/null +++ b/.github/workflows/v4-bootstrap.yml @@ -0,0 +1,106 @@ +# +# @Project: @cldmv/sizeofvar +# @Filename: /.github/workflows/v4-bootstrap.yml +# @Date: 2026-05-26 00:00:00 -07:00 (1780124400) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/v4-bootstrap.yml +# +# Per-repo v4 bootstrap — thin wrapper around the shared +# `org-bootstrap-repo@v4` action. Run once per repo from the Actions tab +# (or, for org-wide rollout, prefer `local-org-onboarding.yml` in +# CLDMV/.github which fans out across many repos in parallel). +# +# What gets applied (overwrite-with-warn — divergences are surfaced in the +# run summary): +# - `next` + `hotfixes` branches created from master HEAD if missing +# - repo settings: allow_auto_merge=true, delete_branch_on_merge=false, +# allow_squash_merge=true, allow_merge_commit=true, +# allow_rebase_merge=false, allow_update_branch=true; plus PR-merge +# dialog defaults (merge_commit_title / squash_merge_commit_title = +# PR_TITLE, merge_commit_message / squash_merge_commit_message = +# PR_BODY) so the resulting commit captures the PR title + body +# verbatim (release-PR body = the categorized changelog → lands on +# master). Per-branch ruleset allowed_merge_methods picks the method. +# - security toggles: dependabot alerts + security updates, secret +# scanning + push protection, private vulnerability reporting +# - rulesets: replaces the three rulesets (Protect Master/Next/Hotfixes) +# with the org canonical defaults +# +# What is NOT applied (GitHub doesn't expose it via REST / GraphQL / gh CLI +# — confirmed against community/community#188598; the bootstrap surfaces +# this as a 'Manual one-time toggles' line in the run summary): +# - Settings → General → Pull Requests → "Auto-close issues with merged +# linked pull requests" (recommended ON). Toggle in the repo UI once. +# +# Idempotent — re-running is safe. Default `dry_run: true` previews +# everything before applying. +# +# Full design: CLDMV/.github docs/conventions/release-flow-v4.md +# Migration checklist: CLDMV/.github docs/migration/v3-to-v4.md +name: 🚀 v4 Bootstrap + +on: + workflow_dispatch: + inputs: + dry_run: + description: "Dry-run: preview every mutation without firing it. Default `true` — set to `false` to actually apply changes." + type: boolean + required: false + default: true + code_security: + description: "Code Security policy. off = disable. public-only = enable only if this repo is public (free). all = enable (paid on private)." + type: choice + required: false + default: "off" + options: + - "off" + - "public-only" + - "all" + secret_protection: + description: "Secret Protection (scanning + push protection) policy. Same shape as code_security." + type: choice + required: false + default: "off" + options: + - "off" + - "public-only" + - "all" + steps: + description: "Subset of phases to run, comma-separated." + required: false + default: "branches,settings,security,rulesets" + +permissions: + contents: read + +jobs: + bootstrap: + name: "🚀 Bootstrap v4 (this repo)" + runs-on: ubuntu-latest + steps: + - name: Create App token + id: app-token + # Full-permission App token — bootstrap needs administration:write + # for security toggles + ruleset import, plus contents:write for + # branch creation. + uses: CLDMV/.github/.github/actions/github/steps/create-app-token@v4 + with: + client_id: ${{ secrets.CLDMV_BOT_APP_CLIENT_ID }} + private_key: ${{ secrets.CLDMV_BOT_APP_PRIVATE_KEY }} + env: + BOT_APP_CLIENT_ID: ${{ secrets.CLDMV_BOT_APP_CLIENT_ID }} + BOT_APP_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_APP_PRIVATE_KEY }} + + - name: Bootstrap + uses: CLDMV/.github/.github/actions/github/jobs/org-bootstrap-repo@v4 + with: + # target_repo defaults to GITHUB_REPOSITORY (this repo). + github_token: ${{ steps.app-token.outputs.token }} + dry_run: ${{ github.event.inputs.dry_run }} + steps: ${{ github.event.inputs.steps }} + code_security: ${{ github.event.inputs.code_security }} + secret_protection: ${{ github.event.inputs.secret_protection }} diff --git a/.github/workflows/welcome.yml b/.github/workflows/welcome.yml new file mode 100644 index 0000000..4b4ba65 --- /dev/null +++ b/.github/workflows/welcome.yml @@ -0,0 +1,38 @@ +# +# @Project: @cldmv/sizeofvar +# @Filename: /.github/workflows/welcome.yml +# @Date: 2026-05-20 00:00:00 -07:00 (1779606000) +# @Author: Nate Corcoran +# @Email: +# @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. +# + +# Individual repo: .github/workflows/welcome.yml +# +# Batch 5.3 from tmp/plan-future-workflows.md. +name: 👋 Welcome Contributor + +# SECURITY NOTE: pull_request_target runs in the BASE repo's context with +# WRITE permissions and access to secrets. SAFE for THIS workflow because: +# - We never checkout the PR head ref +# - We never run code from the PR (no `run:` step uses PR data) +# - We only call REST APIs to read prior interactions and post a comment +# DO NOT add a checkout step or any step that executes PR-supplied content. +on: + issues: + types: [opened] + pull_request_target: + types: [opened] + +permissions: + issues: write + pull-requests: write + +jobs: + welcome: + uses: CLDMV/.github/.github/workflows/reusable-welcome.yml@v4 + # Optional. Without these, the welcome comment is posted by + # github-actions[bot]. With these, it's posted by your CLDMV bot App. + secrets: + BOT_APP_CLIENT_ID: ${{ secrets.CLDMV_BOT_APP_CLIENT_ID }} + BOT_APP_PRIVATE_KEY: ${{ secrets.CLDMV_BOT_APP_PRIVATE_KEY }} diff --git a/package-lock.json b/package-lock.json index e64bdcd..7ef8952 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,4329 +1,1572 @@ { - "name": "sizeofvar", + "name": "@cldmv/sizeofvar", "version": "1.0.4", - "lockfileVersion": 1, + "lockfileVersion": 3, "requires": true, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true + "packages": { + "": { + "name": "@cldmv/sizeofvar", + "version": "1.0.4", + "license": "GPL-3.0", + "devDependencies": { + "@cldmv/vitest-runner": "^1.2.0", + "@vitest/coverage-v8": "^4.1.10", + "vitest": "^4.1.10" + }, + "engines": { + "node": ">=20.19.0" + } }, - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } }, - "cliui": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.0.0.tgz", - "integrity": "sha512-nY3W5Gu2racvdDk//ELReY+dHjb9PlIcVDFXP72nVIhq2Gy3LuVXYwJoPVudwQnv1shtohpgkdCKT2YaKY0CKw==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "dev": true, - "requires": { - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "wrap-ansi": "2.1.0" + "license": "MIT", + "engines": { + "node": ">=6.9.0" } }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true + "node_modules/@babel/parser": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", "dev": true, - "requires": { - "lru-cache": "4.1.1", - "shebang-command": "1.2.0", - "which": "1.3.0" + "license": "MIT", + "engines": { + "node": ">=18" } }, - "decamelize": { + "node_modules/@cldmv/vitest-runner": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true + "resolved": "https://registry.npmjs.org/@cldmv/vitest-runner/-/vitest-runner-1.2.0.tgz", + "integrity": "sha512-RhmXwFNB68OsgnIFSoQeTWgqEAZt/A+MYfc9lf2JdCUIRhzq2Z3gVeuw1pYOV0LihqfPWRNSmaVVDEEQKa93Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.4.1" + }, + "bin": { + "vitest-runner": "bin/vitest-runner.mjs" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "vitest": ">=1.0.0" + } }, - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "node_modules/@emnapi/core": { + "version": "2.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-2.0.0-alpha.3.tgz", + "integrity": "sha512-AZypUeJ/yByuxyS7BlSNRDOMLMlROYtjYdIAuBmJssVz1UJDSeYxLrdizhXCFYhedC5bqd/ASy8EuNXbVVXp9g==", "dev": true, - "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "2.0.1", + "tslib": "^2.4.0" } }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "node_modules/@emnapi/runtime": { + "version": "2.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-2.0.0-alpha.3.tgz", + "integrity": "sha512-hFPAhMUjJD9BSyCANEISPOogeXC9Zo9ZQl7L6vKnaVsMkCtzznaW/naYypeyl0Gv5rYfWYsZbpixTMpjDJzQeA==", "dev": true, - "requires": { - "locate-path": "2.0.0" + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" } }, - "get-caller-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", - "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", - "dev": true + "node_modules/@emnapi/wasi-threads": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-2.0.1.tgz", + "integrity": "sha512-9DsSk+o5NBX0CCJT8s0EROGSGxjR/tKu6aBTaVyq+SjAEQH4XcdcRxPBRzsBLizTTJ49MJjF+jgu3qnO9GLQcQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } }, - "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", - "dev": true + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.2.tgz", + "integrity": "sha512-JfB4kuJQjaoHuCTseIINHtHWeJnvgEcxjwA5t/Y00ZgaOO1Crz3fjT/p8kT28zA/Caz7oiUMn3d6H2yOVCVwuw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.3", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.3" + } }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true + "node_modules/@oxc-project/types": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.142.0.tgz", + "integrity": "sha512-7W+2q5AKQVU36fkaryontrHn3YDt1RyUYXatw9i5H8ocYe2sPKSFB6eS8WNPeRKiN1qAWWZUPm7gwFzJGrccqQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } }, - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.1.tgz", + "integrity": "sha512-02hOeOSryYxVrOIphmLAsqnCJWxwlzFk+pEt/N/i6OgT3lShHO7xGCU5cpgchRDHboAEbSjzgGh+O/u1GswQmA==", + "cpu": [ + "arm64" + ], "dev": true, - "requires": { - "invert-kv": "1.0.0" + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.1.tgz", + "integrity": "sha512-fMsTOnN0OjFm3CyppWPitKnc8UlliVARUULW6cfU6AIqjdtgmSFWSk9vecHzZduv/yMWIHDlRhM1e8Iff9uAfA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.1.tgz", + "integrity": "sha512-1wjKdz/XLGKHaTNHjQveQ/B23TKx4ItAqm1JbyVuvNPc4Ze0Fb48s49TAd/2zcplPl8okE/UbTgmlVfwT7eFeQ==", + "cpu": [ + "x64" + ], "dev": true, - "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "lru-cache": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", - "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.1.tgz", + "integrity": "sha512-Fa0jHR07E7YBN4vOEsbVf2briYNsuOowfLJaXULZM0ldMlaCaj2LJgLMbMe4iacRyZmvR8efFhgR9wKuGclQUg==", + "cpu": [ + "x64" + ], "dev": true, - "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "mem": { + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.1.tgz", + "integrity": "sha512-pzkgu1SSHGgRRyRZ4fbmSgmajbVt+epaLP99NDjFft69v/ypfTi6swBMiVdh2EkQ0OSnHE1lZDM7DRGkyAzUpA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.1.tgz", + "integrity": "sha512-QI5SEDY8cbiYWHx0VO4vIc3UlS6a32vXHjU8Qy/17adEmZIPuByJg13UEvo9c/UCiUkdcVWY83C+b+JrwnNyUg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.1.tgz", + "integrity": "sha512-Sm41FyCeXqmYcERoYOCbGIL5hNfd8w9LQ7Y61Bev48HkcjaJqV/iiVOaiDxjVTRMS+QKrZmD8cfPt4uMVnvM+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.1.tgz", + "integrity": "sha512-2x+WhXTGl9yJYPbltW/BSEPTVz9OIWQyER4N+gJEDWkkn904eRcBzELqh/Hf7K0w/ubGbKNMv0ZC+94QK/IFEg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.1.tgz", + "integrity": "sha512-eEjmQpuRQayHPWWnywaWHkFT3ToPbP3RYy42VVd/B9aBGDA+Ol25EIWHxKQST3IiWJjikCWUF7KtbfqwZrzVwQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.1.tgz", + "integrity": "sha512-/Orga1fZYkLc/56jBICcHrKchl8Z2UKdDSr3LG9ToWO1lQ6a4Livk9Xz+9WN91zsz5QR3XQz2NNoSDEvP6qadw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.1.tgz", + "integrity": "sha512-xxBJRL+0q0Kce7orznGWLuylHDY65vuARXZRpX+hPdv+DqK2c3NlCsVA98tlWzWNEE7yPqA/1NQ5nnCrj49Y5A==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.1.tgz", + "integrity": "sha512-M6AdXIXw3s+/8XpKMzdGDEXGS1S7kwUsy+rcTIUIOx5Ge4nXKCtAFHFV9YKkXvGcC5WMoTjAteLzlsQROVI0Yw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.2.1.tgz", + "integrity": "sha512-/TX0SoRGojHzSAHpfVBbavRVSazg5U3h3Y3VXfcc0cdugq6kxdqw8LPGFiPr+/7gE/60zRcsOY2Vi9b9eT0jww==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "2.0.0-alpha.3", + "@emnapi/runtime": "2.0.0-alpha.3", + "@napi-rs/wasm-runtime": "^1.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.1.tgz", + "integrity": "sha512-EvRrivJieyHG+AO9lleZWgq+g0+S7oV2C51yuqlcyU/R9net+sI4Pj0F+lUoP2bEr6TWX3SqFaaS0SzfLxSzkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.1.tgz", + "integrity": "sha512-Z4eCmn5QJ/5+azF9knpLWKfVd9aidn0mAe9TpJgvBLId9Ax3t0+JVxBmT25Bv7NBbVW1TZyKjQjQReouMeH5UQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", - "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", "dev": true, - "requires": { - "mimic-fn": "1.2.0" + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" } }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" }, - "npm": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/npm/-/npm-5.7.1.tgz", - "integrity": "sha512-r1grvv6mcEt+nlMzMWPc5n/z5q8NNuBWj0TGFp1PBSFCl6ubnAoUGBsucYsnZYT7MOJn0ha1ptEjmdBoAdJ+SA==", - "requires": { - "JSONStream": "1.3.2", - "abbrev": "1.1.1", - "ansi-regex": "3.0.0", - "ansicolors": "0.3.2", - "ansistyles": "0.1.3", - "aproba": "1.2.0", - "archy": "1.0.0", - "bin-links": "1.1.0", - "bluebird": "3.5.1", - "cacache": "10.0.4", - "call-limit": "1.1.0", - "chownr": "1.0.1", - "cli-table2": "0.2.0", - "cmd-shim": "2.0.2", - "columnify": "1.5.4", - "config-chain": "1.1.11", - "debuglog": "1.0.1", - "detect-indent": "5.0.0", - "dezalgo": "1.0.3", - "editor": "1.0.0", - "find-npm-prefix": "1.0.2", - "fs-vacuum": "1.2.10", - "fs-write-stream-atomic": "1.0.10", - "gentle-fs": "2.0.1", - "glob": "7.1.2", - "graceful-fs": "4.1.11", - "has-unicode": "2.0.1", - "hosted-git-info": "2.5.0", - "iferr": "0.1.5", - "imurmurhash": "0.1.4", - "inflight": "1.0.6", - "inherits": "2.0.3", - "ini": "1.3.5", - "init-package-json": "1.10.1", - "is-cidr": "1.0.0", - "lazy-property": "1.0.0", - "libcipm": "1.3.3", - "libnpx": "9.7.1", - "lockfile": "1.0.3", - "lodash._baseindexof": "3.1.0", - "lodash._baseuniq": "4.6.0", - "lodash._bindcallback": "3.0.1", - "lodash._cacheindexof": "3.0.2", - "lodash._createcache": "3.1.2", - "lodash._getnative": "3.9.1", - "lodash.clonedeep": "4.5.0", - "lodash.restparam": "3.6.1", - "lodash.union": "4.6.0", - "lodash.uniq": "4.5.0", - "lodash.without": "4.4.0", - "lru-cache": "4.1.1", - "meant": "1.0.1", - "mississippi": "2.0.0", - "mkdirp": "0.5.1", - "move-concurrently": "1.0.1", - "nopt": "4.0.1", - "normalize-package-data": "2.4.0", - "npm-cache-filename": "1.0.2", - "npm-install-checks": "3.0.0", - "npm-lifecycle": "2.0.0", - "npm-package-arg": "6.0.0", - "npm-packlist": "1.1.10", - "npm-profile": "3.0.1", - "npm-registry-client": "8.5.0", - "npm-user-validate": "1.0.0", - "npmlog": "4.1.2", - "once": "1.4.0", - "opener": "1.4.3", - "osenv": "0.1.5", - "pacote": "7.3.3", - "path-is-inside": "1.0.2", - "promise-inflight": "1.0.1", - "qrcode-terminal": "0.11.0", - "query-string": "5.1.0", - "qw": "1.0.1", - "read": "1.0.7", - "read-cmd-shim": "1.0.1", - "read-installed": "4.0.3", - "read-package-json": "2.0.12", - "read-package-tree": "5.1.6", - "readable-stream": "2.3.4", - "readdir-scoped-modules": "1.0.2", - "request": "2.83.0", - "retry": "0.10.1", - "rimraf": "2.6.2", - "safe-buffer": "5.1.1", - "semver": "5.5.0", - "sha": "2.0.1", - "slide": "1.1.6", - "sorted-object": "2.0.1", - "sorted-union-stream": "2.1.3", - "ssri": "5.2.4", - "strip-ansi": "4.0.0", - "tar": "4.3.3", - "text-table": "0.2.0", - "uid-number": "0.0.6", - "umask": "1.1.0", - "unique-filename": "1.1.0", - "unpipe": "1.0.0", - "update-notifier": "2.3.0", - "uuid": "3.2.1", - "validate-npm-package-license": "3.0.1", - "validate-npm-package-name": "3.0.0", - "which": "1.3.0", - "worker-farm": "1.5.2", - "wrappy": "1.0.2", - "write-file-atomic": "2.1.0" + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitest/coverage-v8": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.10.tgz", + "integrity": "sha512-IM49HmthevbgAO4anp1hwtoT9wYe59w0LR00gr+eagHE+ZJ5lK4sLPeO0ubgoJcwLk6dehU3R24N+FbEEKDc8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.1.10", + "ast-v8-to-istanbul": "^1.0.0", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.2", + "obug": "^2.1.1", + "std-env": "^4.0.0-rc.1", + "tinyrainbow": "^3.1.0" }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "4.1.10", + "vitest": "4.1.10" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", + "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", + "dev": true, + "license": "MIT", "dependencies": { - "JSONStream": { - "version": "1.3.2", - "bundled": true, - "requires": { - "jsonparse": "1.3.1", - "through": "2.3.8" - }, - "dependencies": { - "jsonparse": { - "version": "1.3.1", - "bundled": true - }, - "through": { - "version": "2.3.8", - "bundled": true - } - } - }, - "abbrev": { - "version": "1.1.1", - "bundled": true - }, - "ansi-regex": { - "version": "3.0.0", - "bundled": true - }, - "ansicolors": { - "version": "0.3.2", - "bundled": true - }, - "ansistyles": { - "version": "0.1.3", - "bundled": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true - }, - "archy": { - "version": "1.0.0", - "bundled": true - }, - "bin-links": { - "version": "1.1.0", - "bundled": true, - "requires": { - "bluebird": "3.5.1", - "cmd-shim": "2.0.2", - "fs-write-stream-atomic": "1.0.10", - "gentle-fs": "2.0.1", - "graceful-fs": "4.1.11", - "slide": "1.1.6" - } - }, - "bluebird": { - "version": "3.5.1", - "bundled": true - }, - "cacache": { - "version": "10.0.4", - "bundled": true, - "requires": { - "bluebird": "3.5.1", - "chownr": "1.0.1", - "glob": "7.1.2", - "graceful-fs": "4.1.11", - "lru-cache": "4.1.1", - "mississippi": "2.0.0", - "mkdirp": "0.5.1", - "move-concurrently": "1.0.1", - "promise-inflight": "1.0.1", - "rimraf": "2.6.2", - "ssri": "5.2.4", - "unique-filename": "1.1.0", - "y18n": "4.0.0" - }, - "dependencies": { - "y18n": { - "version": "4.0.0", - "bundled": true - } - } - }, - "call-limit": { - "version": "1.1.0", - "bundled": true - }, - "chownr": { - "version": "1.0.1", - "bundled": true - }, - "cli-table2": { - "version": "0.2.0", - "bundled": true, - "requires": { - "colors": "1.1.2", - "lodash": "3.10.1", - "string-width": "1.0.2" - }, - "dependencies": { - "colors": { - "version": "1.1.2", - "bundled": true, - "optional": true - }, - "lodash": { - "version": "3.10.1", - "bundled": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - }, - "dependencies": { - "code-point-at": { - "version": "1.1.0", - "bundled": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "requires": { - "number-is-nan": "1.0.1" - }, - "dependencies": { - "number-is-nan": { - "version": "1.0.1", - "bundled": true - } - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "bundled": true - } - } - } - } - } - } - }, - "cmd-shim": { - "version": "2.0.2", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "mkdirp": "0.5.1" - } - }, - "columnify": { - "version": "1.5.4", - "bundled": true, - "requires": { - "strip-ansi": "3.0.1", - "wcwidth": "1.0.1" - }, - "dependencies": { - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "bundled": true - } - } - }, - "wcwidth": { - "version": "1.0.1", - "bundled": true, - "requires": { - "defaults": "1.0.3" - }, - "dependencies": { - "defaults": { - "version": "1.0.3", - "bundled": true, - "requires": { - "clone": "1.0.2" - }, - "dependencies": { - "clone": { - "version": "1.0.2", - "bundled": true - } - } - } - } - } - } - }, - "config-chain": { - "version": "1.1.11", - "bundled": true, - "requires": { - "ini": "1.3.5", - "proto-list": "1.2.4" - }, - "dependencies": { - "proto-list": { - "version": "1.2.4", - "bundled": true - } - } - }, - "debuglog": { - "version": "1.0.1", - "bundled": true - }, - "detect-indent": { - "version": "5.0.0", - "bundled": true - }, - "dezalgo": { - "version": "1.0.3", - "bundled": true, - "requires": { - "asap": "2.0.5", - "wrappy": "1.0.2" - }, - "dependencies": { - "asap": { - "version": "2.0.5", - "bundled": true - } - } - }, - "editor": { - "version": "1.0.0", - "bundled": true - }, - "find-npm-prefix": { - "version": "1.0.2", - "bundled": true - }, - "fs-vacuum": { - "version": "1.2.10", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "path-is-inside": "1.0.2", - "rimraf": "2.6.2" - } - }, - "fs-write-stream-atomic": { - "version": "1.0.10", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "iferr": "0.1.5", - "imurmurhash": "0.1.4", - "readable-stream": "2.3.4" - } - }, - "gentle-fs": { - "version": "2.0.1", - "bundled": true, - "requires": { - "aproba": "1.2.0", - "fs-vacuum": "1.2.10", - "graceful-fs": "4.1.11", - "iferr": "0.1.5", - "mkdirp": "0.5.1", - "path-is-inside": "1.0.2", - "read-cmd-shim": "1.0.1", - "slide": "1.1.6" - } - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - }, - "dependencies": { - "fs.realpath": { - "version": "1.0.0", - "bundled": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "1.1.8" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.8", - "bundled": true, - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - }, - "dependencies": { - "balanced-match": { - "version": "1.0.0", - "bundled": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - } - } - } - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true - } - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true - }, - "hosted-git-info": { - "version": "2.5.0", - "bundled": true - }, - "iferr": { - "version": "0.1.5", - "bundled": true - }, - "imurmurhash": { - "version": "0.1.4", - "bundled": true - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true - }, - "ini": { - "version": "1.3.5", - "bundled": true - }, - "init-package-json": { - "version": "1.10.1", - "bundled": true, - "requires": { - "glob": "7.1.2", - "npm-package-arg": "5.1.2", - "promzard": "0.3.0", - "read": "1.0.7", - "read-package-json": "2.0.12", - "semver": "5.5.0", - "validate-npm-package-license": "3.0.1", - "validate-npm-package-name": "3.0.0" - }, - "dependencies": { - "npm-package-arg": { - "version": "5.1.2", - "bundled": true, - "requires": { - "hosted-git-info": "2.5.0", - "osenv": "0.1.5", - "semver": "5.5.0", - "validate-npm-package-name": "3.0.0" - } - }, - "promzard": { - "version": "0.3.0", - "bundled": true, - "requires": { - "read": "1.0.7" - } - } - } - }, - "is-cidr": { - "version": "1.0.0", - "bundled": true, - "requires": { - "cidr-regex": "1.0.6" - }, - "dependencies": { - "cidr-regex": { - "version": "1.0.6", - "bundled": true - } - } - }, - "lazy-property": { - "version": "1.0.0", - "bundled": true - }, - "libcipm": { - "version": "1.3.3", - "bundled": true, - "requires": { - "bin-links": "1.1.0", - "bluebird": "3.5.1", - "find-npm-prefix": "1.0.2", - "graceful-fs": "4.1.11", - "lock-verify": "2.0.0", - "npm-lifecycle": "2.0.0", - "npm-logical-tree": "1.2.1", - "npm-package-arg": "6.0.0", - "pacote": "7.3.3", - "protoduck": "5.0.0", - "read-package-json": "2.0.12", - "rimraf": "2.6.2", - "worker-farm": "1.5.2" - }, - "dependencies": { - "find-npm-prefix": { - "version": "1.0.2", - "bundled": true - }, - "lock-verify": { - "version": "2.0.0", - "bundled": true, - "requires": { - "npm-package-arg": "5.1.2", - "semver": "5.5.0" - }, - "dependencies": { - "npm-package-arg": { - "version": "5.1.2", - "bundled": true, - "requires": { - "hosted-git-info": "2.5.0", - "osenv": "0.1.5", - "semver": "5.5.0", - "validate-npm-package-name": "3.0.0" - } - } - } - }, - "npm-logical-tree": { - "version": "1.2.1", - "bundled": true - }, - "protoduck": { - "version": "5.0.0", - "bundled": true, - "requires": { - "genfun": "4.0.1" - }, - "dependencies": { - "genfun": { - "version": "4.0.1", - "bundled": true - } - } - }, - "worker-farm": { - "version": "1.5.2", - "bundled": true, - "requires": { - "errno": "0.1.7", - "xtend": "4.0.1" - }, - "dependencies": { - "errno": { - "version": "0.1.7", - "bundled": true, - "requires": { - "prr": "1.0.1" - }, - "dependencies": { - "prr": { - "version": "1.0.1", - "bundled": true - } - } - }, - "xtend": { - "version": "4.0.1", - "bundled": true - } - } - } - } - }, - "libnpx": { - "version": "9.7.1", - "bundled": true, - "requires": { - "dotenv": "4.0.0", - "npm-package-arg": "5.1.2", - "rimraf": "2.6.2", - "safe-buffer": "5.1.1", - "update-notifier": "2.3.0", - "which": "1.3.0", - "y18n": "3.2.1", - "yargs": "8.0.2" - }, - "dependencies": { - "dotenv": { - "version": "4.0.0", - "bundled": true - }, - "npm-package-arg": { - "version": "5.1.2", - "bundled": true, - "requires": { - "hosted-git-info": "2.5.0", - "osenv": "0.1.5", - "semver": "5.5.0", - "validate-npm-package-name": "3.0.0" - } - }, - "y18n": { - "version": "3.2.1", - "bundled": true - }, - "yargs": { - "version": "8.0.2", - "bundled": true, - "requires": { - "camelcase": "4.1.0", - "cliui": "3.2.0", - "decamelize": "1.2.0", - "get-caller-file": "1.0.2", - "os-locale": "2.1.0", - "read-pkg-up": "2.0.0", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "2.1.1", - "which-module": "2.0.0", - "y18n": "3.2.1", - "yargs-parser": "7.0.0" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "bundled": true - }, - "cliui": { - "version": "3.2.0", - "bundled": true, - "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wrap-ansi": "2.1.0" - }, - "dependencies": { - "string-width": { - "version": "1.0.2", - "bundled": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - }, - "dependencies": { - "code-point-at": { - "version": "1.1.0", - "bundled": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "requires": { - "number-is-nan": "1.0.1" - }, - "dependencies": { - "number-is-nan": { - "version": "1.0.1", - "bundled": true - } - } - } - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "bundled": true - } - } - }, - "wrap-ansi": { - "version": "2.1.0", - "bundled": true, - "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1" - } - } - } - }, - "decamelize": { - "version": "1.2.0", - "bundled": true - }, - "get-caller-file": { - "version": "1.0.2", - "bundled": true - }, - "os-locale": { - "version": "2.1.0", - "bundled": true, - "requires": { - "execa": "0.7.0", - "lcid": "1.0.0", - "mem": "1.1.0" - }, - "dependencies": { - "execa": { - "version": "0.7.0", - "bundled": true, - "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "5.1.0", - "bundled": true, - "requires": { - "lru-cache": "4.1.1", - "shebang-command": "1.2.0", - "which": "1.3.0" - }, - "dependencies": { - "shebang-command": { - "version": "1.2.0", - "bundled": true, - "requires": { - "shebang-regex": "1.0.0" - }, - "dependencies": { - "shebang-regex": { - "version": "1.0.0", - "bundled": true - } - } - } - } - }, - "get-stream": { - "version": "3.0.0", - "bundled": true - }, - "is-stream": { - "version": "1.1.0", - "bundled": true - }, - "npm-run-path": { - "version": "2.0.2", - "bundled": true, - "requires": { - "path-key": "2.0.1" - }, - "dependencies": { - "path-key": { - "version": "2.0.1", - "bundled": true - } - } - }, - "p-finally": { - "version": "1.0.0", - "bundled": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true - }, - "strip-eof": { - "version": "1.0.0", - "bundled": true - } - } - }, - "lcid": { - "version": "1.0.0", - "bundled": true, - "requires": { - "invert-kv": "1.0.0" - }, - "dependencies": { - "invert-kv": { - "version": "1.0.0", - "bundled": true - } - } - }, - "mem": { - "version": "1.1.0", - "bundled": true, - "requires": { - "mimic-fn": "1.1.0" - }, - "dependencies": { - "mimic-fn": { - "version": "1.1.0", - "bundled": true - } - } - } - } - }, - "read-pkg-up": { - "version": "2.0.0", - "bundled": true, - "requires": { - "find-up": "2.1.0", - "read-pkg": "2.0.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "bundled": true, - "requires": { - "locate-path": "2.0.0" - }, - "dependencies": { - "locate-path": { - "version": "2.0.0", - "bundled": true, - "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" - }, - "dependencies": { - "p-locate": { - "version": "2.0.0", - "bundled": true, - "requires": { - "p-limit": "1.1.0" - }, - "dependencies": { - "p-limit": { - "version": "1.1.0", - "bundled": true - } - } - }, - "path-exists": { - "version": "3.0.0", - "bundled": true - } - } - } - } - }, - "read-pkg": { - "version": "2.0.0", - "bundled": true, - "requires": { - "load-json-file": "2.0.0", - "normalize-package-data": "2.4.0", - "path-type": "2.0.0" - }, - "dependencies": { - "load-json-file": { - "version": "2.0.0", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "strip-bom": "3.0.0" - }, - "dependencies": { - "parse-json": { - "version": "2.2.0", - "bundled": true, - "requires": { - "error-ex": "1.3.1" - }, - "dependencies": { - "error-ex": { - "version": "1.3.1", - "bundled": true, - "requires": { - "is-arrayish": "0.2.1" - }, - "dependencies": { - "is-arrayish": { - "version": "0.2.1", - "bundled": true - } - } - } - } - }, - "pify": { - "version": "2.3.0", - "bundled": true - }, - "strip-bom": { - "version": "3.0.0", - "bundled": true - } - } - }, - "path-type": { - "version": "2.0.0", - "bundled": true, - "requires": { - "pify": "2.3.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "bundled": true - } - } - } - } - } - } - }, - "require-directory": { - "version": "2.1.1", - "bundled": true - }, - "require-main-filename": { - "version": "1.0.1", - "bundled": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true - }, - "string-width": { - "version": "2.1.1", - "bundled": true, - "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true - } - } - }, - "which-module": { - "version": "2.0.0", - "bundled": true - }, - "yargs-parser": { - "version": "7.0.0", - "bundled": true, - "requires": { - "camelcase": "4.1.0" - } - } - } - } - } - }, - "lockfile": { - "version": "1.0.3", - "bundled": true - }, - "lodash._baseindexof": { - "version": "3.1.0", - "bundled": true - }, - "lodash._baseuniq": { - "version": "4.6.0", - "bundled": true, - "requires": { - "lodash._createset": "4.0.3", - "lodash._root": "3.0.1" - }, - "dependencies": { - "lodash._createset": { - "version": "4.0.3", - "bundled": true - }, - "lodash._root": { - "version": "3.0.1", - "bundled": true - } - } - }, - "lodash._bindcallback": { - "version": "3.0.1", - "bundled": true - }, - "lodash._cacheindexof": { - "version": "3.0.2", - "bundled": true - }, - "lodash._createcache": { - "version": "3.1.2", - "bundled": true, - "requires": { - "lodash._getnative": "3.9.1" - } - }, - "lodash._getnative": { - "version": "3.9.1", - "bundled": true - }, - "lodash.clonedeep": { - "version": "4.5.0", - "bundled": true - }, - "lodash.restparam": { - "version": "3.6.1", - "bundled": true - }, - "lodash.union": { - "version": "4.6.0", - "bundled": true - }, - "lodash.uniq": { - "version": "4.5.0", - "bundled": true - }, - "lodash.without": { - "version": "4.4.0", - "bundled": true - }, - "lru-cache": { - "version": "4.1.1", - "bundled": true, - "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" - }, - "dependencies": { - "pseudomap": { - "version": "1.0.2", - "bundled": true - }, - "yallist": { - "version": "2.1.2", - "bundled": true - } - } - }, - "meant": { - "version": "1.0.1", - "bundled": true - }, - "mississippi": { - "version": "2.0.0", - "bundled": true, - "requires": { - "concat-stream": "1.6.0", - "duplexify": "3.5.3", - "end-of-stream": "1.4.1", - "flush-write-stream": "1.0.2", - "from2": "2.3.0", - "parallel-transform": "1.1.0", - "pump": "2.0.1", - "pumpify": "1.4.0", - "stream-each": "1.2.2", - "through2": "2.0.3" - }, - "dependencies": { - "concat-stream": { - "version": "1.6.0", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.4", - "typedarray": "0.0.6" - }, - "dependencies": { - "typedarray": { - "version": "0.0.6", - "bundled": true - } - } - }, - "duplexify": { - "version": "3.5.3", - "bundled": true, - "requires": { - "end-of-stream": "1.4.1", - "inherits": "2.0.3", - "readable-stream": "2.3.4", - "stream-shift": "1.0.0" - }, - "dependencies": { - "stream-shift": { - "version": "1.0.0", - "bundled": true - } - } - }, - "end-of-stream": { - "version": "1.4.1", - "bundled": true, - "requires": { - "once": "1.4.0" - } - }, - "flush-write-stream": { - "version": "1.0.2", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.4" - } - }, - "from2": { - "version": "2.3.0", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.4" - } - }, - "parallel-transform": { - "version": "1.1.0", - "bundled": true, - "requires": { - "cyclist": "0.2.2", - "inherits": "2.0.3", - "readable-stream": "2.3.4" - }, - "dependencies": { - "cyclist": { - "version": "0.2.2", - "bundled": true - } - } - }, - "pump": { - "version": "2.0.1", - "bundled": true, - "requires": { - "end-of-stream": "1.4.1", - "once": "1.4.0" - } - }, - "pumpify": { - "version": "1.4.0", - "bundled": true, - "requires": { - "duplexify": "3.5.3", - "inherits": "2.0.3", - "pump": "2.0.1" - } - }, - "stream-each": { - "version": "1.2.2", - "bundled": true, - "requires": { - "end-of-stream": "1.4.1", - "stream-shift": "1.0.0" - }, - "dependencies": { - "stream-shift": { - "version": "1.0.0", - "bundled": true - } - } - }, - "through2": { - "version": "2.0.3", - "bundled": true, - "requires": { - "readable-stream": "2.3.4", - "xtend": "4.0.1" - }, - "dependencies": { - "xtend": { - "version": "4.0.1", - "bundled": true - } - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "bundled": true - } - } - }, - "move-concurrently": { - "version": "1.0.1", - "bundled": true, - "requires": { - "aproba": "1.2.0", - "copy-concurrently": "1.0.5", - "fs-write-stream-atomic": "1.0.10", - "mkdirp": "0.5.1", - "rimraf": "2.6.2", - "run-queue": "1.0.3" - }, - "dependencies": { - "copy-concurrently": { - "version": "1.0.5", - "bundled": true, - "requires": { - "aproba": "1.2.0", - "fs-write-stream-atomic": "1.0.10", - "iferr": "0.1.5", - "mkdirp": "0.5.1", - "rimraf": "2.6.2", - "run-queue": "1.0.3" - } - }, - "run-queue": { - "version": "1.0.3", - "bundled": true, - "requires": { - "aproba": "1.2.0" - } - } - } - }, - "node-gyp": { - "version": "3.6.2", - "bundled": true, - "requires": { - "fstream": "1.0.11", - "glob": "7.1.2", - "graceful-fs": "4.1.11", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "nopt": "3.0.6", - "npmlog": "4.1.2", - "osenv": "0.1.5", - "request": "2.83.0", - "rimraf": "2.6.2", - "semver": "5.3.0", - "tar": "2.2.1", - "which": "1.3.0" - }, - "dependencies": { - "fstream": { - "version": "1.0.11", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.6.2" - } - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "1.1.8" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.8", - "bundled": true, - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - }, - "dependencies": { - "balanced-match": { - "version": "1.0.0", - "bundled": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - } - } - } - } - }, - "nopt": { - "version": "3.0.6", - "bundled": true, - "requires": { - "abbrev": "1.1.1" - } - }, - "semver": { - "version": "5.3.0", - "bundled": true - }, - "tar": { - "version": "2.2.1", - "bundled": true, - "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.11", - "inherits": "2.0.3" - }, - "dependencies": { - "block-stream": { - "version": "0.0.9", - "bundled": true, - "requires": { - "inherits": "2.0.3" - } - } - } - } - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "requires": { - "abbrev": "1.1.1", - "osenv": "0.1.5" - } - }, - "normalize-package-data": { - "version": "2.4.0", - "bundled": true, - "requires": { - "hosted-git-info": "2.5.0", - "is-builtin-module": "1.0.0", - "semver": "5.5.0", - "validate-npm-package-license": "3.0.1" - }, - "dependencies": { - "is-builtin-module": { - "version": "1.0.0", - "bundled": true, - "requires": { - "builtin-modules": "1.1.1" - }, - "dependencies": { - "builtin-modules": { - "version": "1.1.1", - "bundled": true - } - } - } - } - }, - "npm-cache-filename": { - "version": "1.0.2", - "bundled": true - }, - "npm-install-checks": { - "version": "3.0.0", - "bundled": true, - "requires": { - "semver": "5.5.0" - } - }, - "npm-lifecycle": { - "version": "2.0.0", - "bundled": true, - "requires": { - "byline": "5.0.0", - "graceful-fs": "4.1.11", - "node-gyp": "3.6.2", - "resolve-from": "4.0.0", - "slide": "1.1.6", - "uid-number": "0.0.6", - "umask": "1.1.0", - "which": "1.3.0" - }, - "dependencies": { - "byline": { - "version": "5.0.0", - "bundled": true - }, - "resolve-from": { - "version": "4.0.0", - "bundled": true - } - } - }, - "npm-package-arg": { - "version": "6.0.0", - "bundled": true, - "requires": { - "hosted-git-info": "2.5.0", - "osenv": "0.1.5", - "semver": "5.5.0", - "validate-npm-package-name": "3.0.0" - } - }, - "npm-packlist": { - "version": "1.1.10", - "bundled": true, - "requires": { - "ignore-walk": "3.0.1", - "npm-bundled": "1.0.3" - }, - "dependencies": { - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "requires": { - "minimatch": "3.0.4" - }, - "dependencies": { - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "1.1.8" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.8", - "bundled": true, - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - }, - "dependencies": { - "balanced-match": { - "version": "1.0.0", - "bundled": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - } - } - } - } - } - } - }, - "npm-bundled": { - "version": "1.0.3", - "bundled": true - } - } - }, - "npm-profile": { - "version": "3.0.1", - "bundled": true, - "requires": { - "aproba": "1.2.0", - "make-fetch-happen": "2.6.0" - }, - "dependencies": { - "make-fetch-happen": { - "version": "2.6.0", - "bundled": true, - "requires": { - "agentkeepalive": "3.3.0", - "cacache": "10.0.4", - "http-cache-semantics": "3.8.1", - "http-proxy-agent": "2.0.0", - "https-proxy-agent": "2.1.1", - "lru-cache": "4.1.1", - "mississippi": "1.3.1", - "node-fetch-npm": "2.0.2", - "promise-retry": "1.1.1", - "socks-proxy-agent": "3.0.1", - "ssri": "5.2.4" - }, - "dependencies": { - "agentkeepalive": { - "version": "3.3.0", - "bundled": true, - "requires": { - "humanize-ms": "1.2.1" - }, - "dependencies": { - "humanize-ms": { - "version": "1.2.1", - "bundled": true, - "requires": { - "ms": "2.1.1" - }, - "dependencies": { - "ms": { - "version": "2.1.1", - "bundled": true - } - } - } - } - }, - "http-cache-semantics": { - "version": "3.8.1", - "bundled": true - }, - "http-proxy-agent": { - "version": "2.0.0", - "bundled": true, - "requires": { - "agent-base": "4.2.0", - "debug": "2.6.9" - }, - "dependencies": { - "agent-base": { - "version": "4.2.0", - "bundled": true, - "requires": { - "es6-promisify": "5.0.0" - }, - "dependencies": { - "es6-promisify": { - "version": "5.0.0", - "bundled": true, - "requires": { - "es6-promise": "4.2.4" - }, - "dependencies": { - "es6-promise": { - "version": "4.2.4", - "bundled": true - } - } - } - } - }, - "debug": { - "version": "2.6.9", - "bundled": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "bundled": true - } - } - } - } - }, - "https-proxy-agent": { - "version": "2.1.1", - "bundled": true, - "requires": { - "agent-base": "4.2.0", - "debug": "3.1.0" - }, - "dependencies": { - "agent-base": { - "version": "4.2.0", - "bundled": true, - "requires": { - "es6-promisify": "5.0.0" - }, - "dependencies": { - "es6-promisify": { - "version": "5.0.0", - "bundled": true, - "requires": { - "es6-promise": "4.2.4" - }, - "dependencies": { - "es6-promise": { - "version": "4.2.4", - "bundled": true - } - } - } - } - }, - "debug": { - "version": "3.1.0", - "bundled": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "bundled": true - } - } - } - } - }, - "mississippi": { - "version": "1.3.1", - "bundled": true, - "requires": { - "concat-stream": "1.6.0", - "duplexify": "3.5.3", - "end-of-stream": "1.4.1", - "flush-write-stream": "1.0.2", - "from2": "2.3.0", - "parallel-transform": "1.1.0", - "pump": "1.0.3", - "pumpify": "1.4.0", - "stream-each": "1.2.2", - "through2": "2.0.3" - }, - "dependencies": { - "concat-stream": { - "version": "1.6.0", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.4", - "typedarray": "0.0.6" - }, - "dependencies": { - "typedarray": { - "version": "0.0.6", - "bundled": true - } - } - }, - "duplexify": { - "version": "3.5.3", - "bundled": true, - "requires": { - "end-of-stream": "1.4.1", - "inherits": "2.0.3", - "readable-stream": "2.3.4", - "stream-shift": "1.0.0" - }, - "dependencies": { - "stream-shift": { - "version": "1.0.0", - "bundled": true - } - } - }, - "end-of-stream": { - "version": "1.4.1", - "bundled": true, - "requires": { - "once": "1.4.0" - } - }, - "flush-write-stream": { - "version": "1.0.2", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.4" - } - }, - "from2": { - "version": "2.3.0", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.4" - } - }, - "parallel-transform": { - "version": "1.1.0", - "bundled": true, - "requires": { - "cyclist": "0.2.2", - "inherits": "2.0.3", - "readable-stream": "2.3.4" - }, - "dependencies": { - "cyclist": { - "version": "0.2.2", - "bundled": true - } - } - }, - "pump": { - "version": "1.0.3", - "bundled": true, - "requires": { - "end-of-stream": "1.4.1", - "once": "1.4.0" - } - }, - "pumpify": { - "version": "1.4.0", - "bundled": true, - "requires": { - "duplexify": "3.5.3", - "inherits": "2.0.3", - "pump": "2.0.1" - }, - "dependencies": { - "pump": { - "version": "2.0.1", - "bundled": true, - "requires": { - "end-of-stream": "1.4.1", - "once": "1.4.0" - } - } - } - }, - "stream-each": { - "version": "1.2.2", - "bundled": true, - "requires": { - "end-of-stream": "1.4.1", - "stream-shift": "1.0.0" - }, - "dependencies": { - "stream-shift": { - "version": "1.0.0", - "bundled": true - } - } - }, - "through2": { - "version": "2.0.3", - "bundled": true, - "requires": { - "readable-stream": "2.3.4", - "xtend": "4.0.1" - }, - "dependencies": { - "xtend": { - "version": "4.0.1", - "bundled": true - } - } - } - } - }, - "node-fetch-npm": { - "version": "2.0.2", - "bundled": true, - "requires": { - "encoding": "0.1.12", - "json-parse-better-errors": "1.0.1", - "safe-buffer": "5.1.1" - }, - "dependencies": { - "encoding": { - "version": "0.1.12", - "bundled": true, - "requires": { - "iconv-lite": "0.4.19" - }, - "dependencies": { - "iconv-lite": { - "version": "0.4.19", - "bundled": true - } - } - }, - "json-parse-better-errors": { - "version": "1.0.1", - "bundled": true - } - } - }, - "promise-retry": { - "version": "1.1.1", - "bundled": true, - "requires": { - "err-code": "1.1.2", - "retry": "0.10.1" - }, - "dependencies": { - "err-code": { - "version": "1.1.2", - "bundled": true - } - } - }, - "socks-proxy-agent": { - "version": "3.0.1", - "bundled": true, - "requires": { - "agent-base": "4.2.0", - "socks": "1.1.10" - }, - "dependencies": { - "agent-base": { - "version": "4.2.0", - "bundled": true, - "requires": { - "es6-promisify": "5.0.0" - }, - "dependencies": { - "es6-promisify": { - "version": "5.0.0", - "bundled": true, - "requires": { - "es6-promise": "4.2.4" - }, - "dependencies": { - "es6-promise": { - "version": "4.2.4", - "bundled": true - } - } - } - } - }, - "socks": { - "version": "1.1.10", - "bundled": true, - "requires": { - "ip": "1.1.5", - "smart-buffer": "1.1.15" - }, - "dependencies": { - "ip": { - "version": "1.1.5", - "bundled": true - }, - "smart-buffer": { - "version": "1.1.15", - "bundled": true - } - } - } - } - } - } - } - } - }, - "npm-registry-client": { - "version": "8.5.0", - "bundled": true, - "requires": { - "concat-stream": "1.6.0", - "graceful-fs": "4.1.11", - "normalize-package-data": "2.4.0", - "npm-package-arg": "5.1.2", - "npmlog": "4.1.2", - "once": "1.4.0", - "request": "2.83.0", - "retry": "0.10.1", - "semver": "5.5.0", - "slide": "1.1.6", - "ssri": "4.1.6" - }, - "dependencies": { - "concat-stream": { - "version": "1.6.0", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.4", - "typedarray": "0.0.6" - }, - "dependencies": { - "typedarray": { - "version": "0.0.6", - "bundled": true - } - } - }, - "npm-package-arg": { - "version": "5.1.2", - "bundled": true, - "requires": { - "hosted-git-info": "2.5.0", - "osenv": "0.1.5", - "semver": "5.5.0", - "validate-npm-package-name": "3.0.0" - } - }, - "ssri": { - "version": "4.1.6", - "bundled": true, - "requires": { - "safe-buffer": "5.1.1" - } - } - } - }, - "npm-user-validate": { - "version": "1.0.0", - "bundled": true - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" - }, - "dependencies": { - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "requires": { - "delegates": "1.0.0", - "readable-stream": "2.3.4" - }, - "dependencies": { - "delegates": { - "version": "1.0.0", - "bundled": true - } - } - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "requires": { - "aproba": "1.2.0", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" - }, - "dependencies": { - "object-assign": { - "version": "4.1.1", - "bundled": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - }, - "dependencies": { - "code-point-at": { - "version": "1.1.0", - "bundled": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "requires": { - "number-is-nan": "1.0.1" - }, - "dependencies": { - "number-is-nan": { - "version": "1.0.1", - "bundled": true - } - } - } - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "bundled": true - } - } - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "requires": { - "string-width": "1.0.2" - } - } - } - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true - } - } - }, - "once": { - "version": "1.4.0", - "bundled": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "opener": { - "version": "1.4.3", - "bundled": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - }, - "dependencies": { - "os-homedir": { - "version": "1.0.2", - "bundled": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true - } - } - }, - "pacote": { - "version": "7.3.3", - "bundled": true, - "requires": { - "bluebird": "3.5.1", - "cacache": "10.0.4", - "get-stream": "3.0.0", - "glob": "7.1.2", - "lru-cache": "4.1.1", - "make-fetch-happen": "2.6.0", - "minimatch": "3.0.4", - "mississippi": "2.0.0", - "normalize-package-data": "2.4.0", - "npm-package-arg": "6.0.0", - "npm-packlist": "1.1.10", - "npm-pick-manifest": "2.1.0", - "osenv": "0.1.5", - "promise-inflight": "1.0.1", - "promise-retry": "1.1.1", - "protoduck": "5.0.0", - "safe-buffer": "5.1.1", - "semver": "5.5.0", - "ssri": "5.2.4", - "tar": "4.3.3", - "unique-filename": "1.1.0", - "which": "1.3.0" - }, - "dependencies": { - "get-stream": { - "version": "3.0.0", - "bundled": true - }, - "make-fetch-happen": { - "version": "2.6.0", - "bundled": true, - "requires": { - "agentkeepalive": "3.3.0", - "cacache": "10.0.4", - "http-cache-semantics": "3.8.1", - "http-proxy-agent": "2.0.0", - "https-proxy-agent": "2.1.1", - "lru-cache": "4.1.1", - "mississippi": "1.3.1", - "node-fetch-npm": "2.0.2", - "promise-retry": "1.1.1", - "socks-proxy-agent": "3.0.1", - "ssri": "5.2.4" - }, - "dependencies": { - "agentkeepalive": { - "version": "3.3.0", - "bundled": true, - "requires": { - "humanize-ms": "1.2.1" - }, - "dependencies": { - "humanize-ms": { - "version": "1.2.1", - "bundled": true, - "requires": { - "ms": "2.1.1" - }, - "dependencies": { - "ms": { - "version": "2.1.1", - "bundled": true - } - } - } - } - }, - "http-cache-semantics": { - "version": "3.8.1", - "bundled": true - }, - "http-proxy-agent": { - "version": "2.0.0", - "bundled": true, - "requires": { - "agent-base": "4.2.0", - "debug": "2.6.9" - }, - "dependencies": { - "agent-base": { - "version": "4.2.0", - "bundled": true, - "requires": { - "es6-promisify": "5.0.0" - }, - "dependencies": { - "es6-promisify": { - "version": "5.0.0", - "bundled": true, - "requires": { - "es6-promise": "4.2.4" - }, - "dependencies": { - "es6-promise": { - "version": "4.2.4", - "bundled": true - } - } - } - } - }, - "debug": { - "version": "2.6.9", - "bundled": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "bundled": true - } - } - } - } - }, - "https-proxy-agent": { - "version": "2.1.1", - "bundled": true, - "requires": { - "agent-base": "4.2.0", - "debug": "3.1.0" - }, - "dependencies": { - "agent-base": { - "version": "4.2.0", - "bundled": true, - "requires": { - "es6-promisify": "5.0.0" - }, - "dependencies": { - "es6-promisify": { - "version": "5.0.0", - "bundled": true, - "requires": { - "es6-promise": "4.2.4" - }, - "dependencies": { - "es6-promise": { - "version": "4.2.4", - "bundled": true - } - } - } - } - }, - "debug": { - "version": "3.1.0", - "bundled": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "bundled": true - } - } - } - } - }, - "mississippi": { - "version": "1.3.1", - "bundled": true, - "requires": { - "concat-stream": "1.6.0", - "duplexify": "3.5.3", - "end-of-stream": "1.4.1", - "flush-write-stream": "1.0.2", - "from2": "2.3.0", - "parallel-transform": "1.1.0", - "pump": "1.0.3", - "pumpify": "1.4.0", - "stream-each": "1.2.2", - "through2": "2.0.3" - }, - "dependencies": { - "concat-stream": { - "version": "1.6.0", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.4", - "typedarray": "0.0.6" - }, - "dependencies": { - "typedarray": { - "version": "0.0.6", - "bundled": true - } - } - }, - "duplexify": { - "version": "3.5.3", - "bundled": true, - "requires": { - "end-of-stream": "1.4.1", - "inherits": "2.0.3", - "readable-stream": "2.3.4", - "stream-shift": "1.0.0" - }, - "dependencies": { - "stream-shift": { - "version": "1.0.0", - "bundled": true - } - } - }, - "end-of-stream": { - "version": "1.4.1", - "bundled": true, - "requires": { - "once": "1.4.0" - } - }, - "flush-write-stream": { - "version": "1.0.2", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.4" - } - }, - "from2": { - "version": "2.3.0", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.4" - } - }, - "parallel-transform": { - "version": "1.1.0", - "bundled": true, - "requires": { - "cyclist": "0.2.2", - "inherits": "2.0.3", - "readable-stream": "2.3.4" - }, - "dependencies": { - "cyclist": { - "version": "0.2.2", - "bundled": true - } - } - }, - "pump": { - "version": "1.0.3", - "bundled": true, - "requires": { - "end-of-stream": "1.4.1", - "once": "1.4.0" - } - }, - "pumpify": { - "version": "1.4.0", - "bundled": true, - "requires": { - "duplexify": "3.5.3", - "inherits": "2.0.3", - "pump": "2.0.1" - }, - "dependencies": { - "pump": { - "version": "2.0.1", - "bundled": true, - "requires": { - "end-of-stream": "1.4.1", - "once": "1.4.0" - } - } - } - }, - "stream-each": { - "version": "1.2.2", - "bundled": true, - "requires": { - "end-of-stream": "1.4.1", - "stream-shift": "1.0.0" - }, - "dependencies": { - "stream-shift": { - "version": "1.0.0", - "bundled": true - } - } - }, - "through2": { - "version": "2.0.3", - "bundled": true, - "requires": { - "readable-stream": "2.3.4", - "xtend": "4.0.1" - }, - "dependencies": { - "xtend": { - "version": "4.0.1", - "bundled": true - } - } - } - } - }, - "node-fetch-npm": { - "version": "2.0.2", - "bundled": true, - "requires": { - "encoding": "0.1.12", - "json-parse-better-errors": "1.0.1", - "safe-buffer": "5.1.1" - }, - "dependencies": { - "encoding": { - "version": "0.1.12", - "bundled": true, - "requires": { - "iconv-lite": "0.4.19" - }, - "dependencies": { - "iconv-lite": { - "version": "0.4.19", - "bundled": true - } - } - }, - "json-parse-better-errors": { - "version": "1.0.1", - "bundled": true - } - } - }, - "socks-proxy-agent": { - "version": "3.0.1", - "bundled": true, - "requires": { - "agent-base": "4.2.0", - "socks": "1.1.10" - }, - "dependencies": { - "agent-base": { - "version": "4.2.0", - "bundled": true, - "requires": { - "es6-promisify": "5.0.0" - }, - "dependencies": { - "es6-promisify": { - "version": "5.0.0", - "bundled": true, - "requires": { - "es6-promise": "4.2.4" - }, - "dependencies": { - "es6-promise": { - "version": "4.2.4", - "bundled": true - } - } - } - } - }, - "socks": { - "version": "1.1.10", - "bundled": true, - "requires": { - "ip": "1.1.5", - "smart-buffer": "1.1.15" - }, - "dependencies": { - "ip": { - "version": "1.1.5", - "bundled": true - }, - "smart-buffer": { - "version": "1.1.15", - "bundled": true - } - } - } - } - } - } - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "1.1.11" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - }, - "dependencies": { - "balanced-match": { - "version": "1.0.0", - "bundled": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - } - } - } - } - }, - "mississippi": { - "version": "2.0.0", - "bundled": true, - "requires": { - "concat-stream": "1.6.0", - "duplexify": "3.5.3", - "end-of-stream": "1.4.1", - "flush-write-stream": "1.0.2", - "from2": "2.3.0", - "parallel-transform": "1.1.0", - "pump": "2.0.1", - "pumpify": "1.4.0", - "stream-each": "1.2.2", - "through2": "2.0.3" - }, - "dependencies": { - "concat-stream": { - "version": "1.6.0", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.4", - "typedarray": "0.0.6" - }, - "dependencies": { - "typedarray": { - "version": "0.0.6", - "bundled": true - } - } - }, - "duplexify": { - "version": "3.5.3", - "bundled": true, - "requires": { - "end-of-stream": "1.4.1", - "inherits": "2.0.3", - "readable-stream": "2.3.4", - "stream-shift": "1.0.0" - }, - "dependencies": { - "stream-shift": { - "version": "1.0.0", - "bundled": true - } - } - }, - "end-of-stream": { - "version": "1.4.1", - "bundled": true, - "requires": { - "once": "1.4.0" - } - }, - "flush-write-stream": { - "version": "1.0.2", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.4" - } - }, - "from2": { - "version": "2.3.0", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.4" - } - }, - "parallel-transform": { - "version": "1.1.0", - "bundled": true, - "requires": { - "cyclist": "0.2.2", - "inherits": "2.0.3", - "readable-stream": "2.3.4" - }, - "dependencies": { - "cyclist": { - "version": "0.2.2", - "bundled": true - } - } - }, - "pump": { - "version": "2.0.1", - "bundled": true, - "requires": { - "end-of-stream": "1.4.1", - "once": "1.4.0" - } - }, - "pumpify": { - "version": "1.4.0", - "bundled": true, - "requires": { - "duplexify": "3.5.3", - "inherits": "2.0.3", - "pump": "2.0.1" - } - }, - "stream-each": { - "version": "1.2.2", - "bundled": true, - "requires": { - "end-of-stream": "1.4.1", - "stream-shift": "1.0.0" - }, - "dependencies": { - "stream-shift": { - "version": "1.0.0", - "bundled": true - } - } - }, - "through2": { - "version": "2.0.3", - "bundled": true, - "requires": { - "readable-stream": "2.3.4", - "xtend": "4.0.1" - }, - "dependencies": { - "xtend": { - "version": "4.0.1", - "bundled": true - } - } - } - } - }, - "npm-pick-manifest": { - "version": "2.1.0", - "bundled": true, - "requires": { - "npm-package-arg": "6.0.0", - "semver": "5.5.0" - } - }, - "promise-retry": { - "version": "1.1.1", - "bundled": true, - "requires": { - "err-code": "1.1.2", - "retry": "0.10.1" - }, - "dependencies": { - "err-code": { - "version": "1.1.2", - "bundled": true - } - } - }, - "protoduck": { - "version": "5.0.0", - "bundled": true, - "requires": { - "genfun": "4.0.1" - }, - "dependencies": { - "genfun": { - "version": "4.0.1", - "bundled": true - } - } - }, - "semver": { - "version": "5.5.0", - "bundled": true - } - } - }, - "path-is-inside": { - "version": "1.0.2", - "bundled": true - }, - "promise-inflight": { - "version": "1.0.1", - "bundled": true - }, - "qrcode-terminal": { - "version": "0.11.0", - "bundled": true - }, - "query-string": { - "version": "5.1.0", - "bundled": true, - "requires": { - "decode-uri-component": "0.2.0", - "object-assign": "4.1.1", - "strict-uri-encode": "1.1.0" - }, - "dependencies": { - "decode-uri-component": { - "version": "0.2.0", - "bundled": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true - }, - "strict-uri-encode": { - "version": "1.1.0", - "bundled": true - } - } - }, - "qw": { - "version": "1.0.1", - "bundled": true - }, - "read": { - "version": "1.0.7", - "bundled": true, - "requires": { - "mute-stream": "0.0.7" - }, - "dependencies": { - "mute-stream": { - "version": "0.0.7", - "bundled": true - } - } - }, - "read-cmd-shim": { - "version": "1.0.1", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11" - } - }, - "read-installed": { - "version": "4.0.3", - "bundled": true, - "requires": { - "debuglog": "1.0.1", - "graceful-fs": "4.1.11", - "read-package-json": "2.0.12", - "readdir-scoped-modules": "1.0.2", - "semver": "5.5.0", - "slide": "1.1.6", - "util-extend": "1.0.3" - }, - "dependencies": { - "util-extend": { - "version": "1.0.3", - "bundled": true - } - } - }, - "read-package-json": { - "version": "2.0.12", - "bundled": true, - "requires": { - "glob": "7.1.2", - "graceful-fs": "4.1.11", - "json-parse-better-errors": "1.0.1", - "normalize-package-data": "2.4.0", - "slash": "1.0.0" - }, - "dependencies": { - "json-parse-better-errors": { - "version": "1.0.1", - "bundled": true - }, - "slash": { - "version": "1.0.0", - "bundled": true - } - } - }, - "read-package-tree": { - "version": "5.1.6", - "bundled": true, - "requires": { - "debuglog": "1.0.1", - "dezalgo": "1.0.3", - "once": "1.4.0", - "read-package-json": "2.0.12", - "readdir-scoped-modules": "1.0.2" - } - }, - "readable-stream": { - "version": "2.3.4", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" - }, - "dependencies": { - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true - }, - "string_decoder": { - "version": "1.0.3", - "bundled": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - } - } - }, - "readdir-scoped-modules": { - "version": "1.0.2", - "bundled": true, - "requires": { - "debuglog": "1.0.1", - "dezalgo": "1.0.3", - "graceful-fs": "4.1.11", - "once": "1.4.0" - } - }, - "request": { - "version": "2.83.0", - "bundled": true, - "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.3.1", - "har-validator": "5.0.3", - "hawk": "6.0.2", - "http-signature": "1.2.0", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.17", - "oauth-sign": "0.8.2", - "performance-now": "2.1.0", - "qs": "6.5.1", - "safe-buffer": "5.1.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.3", - "tunnel-agent": "0.6.0", - "uuid": "3.2.1" - }, - "dependencies": { - "aws-sign2": { - "version": "0.7.0", - "bundled": true - }, - "aws4": { - "version": "1.6.0", - "bundled": true - }, - "caseless": { - "version": "0.12.0", - "bundled": true - }, - "combined-stream": { - "version": "1.0.5", - "bundled": true, - "requires": { - "delayed-stream": "1.0.0" - }, - "dependencies": { - "delayed-stream": { - "version": "1.0.0", - "bundled": true - } - } - }, - "extend": { - "version": "3.0.1", - "bundled": true - }, - "forever-agent": { - "version": "0.6.1", - "bundled": true - }, - "form-data": { - "version": "2.3.1", - "bundled": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.17" - }, - "dependencies": { - "asynckit": { - "version": "0.4.0", - "bundled": true - } - } - }, - "har-validator": { - "version": "5.0.3", - "bundled": true, - "requires": { - "ajv": "5.2.3", - "har-schema": "2.0.0" - }, - "dependencies": { - "ajv": { - "version": "5.2.3", - "bundled": true, - "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.0.0", - "json-schema-traverse": "0.3.1", - "json-stable-stringify": "1.0.1" - }, - "dependencies": { - "co": { - "version": "4.6.0", - "bundled": true - }, - "fast-deep-equal": { - "version": "1.0.0", - "bundled": true - }, - "json-schema-traverse": { - "version": "0.3.1", - "bundled": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "bundled": true, - "requires": { - "jsonify": "0.0.0" - }, - "dependencies": { - "jsonify": { - "version": "0.0.0", - "bundled": true - } - } - } - } - }, - "har-schema": { - "version": "2.0.0", - "bundled": true - } - } - }, - "hawk": { - "version": "6.0.2", - "bundled": true, - "requires": { - "boom": "4.3.1", - "cryptiles": "3.1.2", - "hoek": "4.2.0", - "sntp": "2.0.2" - }, - "dependencies": { - "boom": { - "version": "4.3.1", - "bundled": true, - "requires": { - "hoek": "4.2.0" - } - }, - "cryptiles": { - "version": "3.1.2", - "bundled": true, - "requires": { - "boom": "5.2.0" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "bundled": true, - "requires": { - "hoek": "4.2.0" - } - } - } - }, - "hoek": { - "version": "4.2.0", - "bundled": true - }, - "sntp": { - "version": "2.0.2", - "bundled": true, - "requires": { - "hoek": "4.2.0" - } - } - } - }, - "http-signature": { - "version": "1.2.0", - "bundled": true, - "requires": { - "assert-plus": "1.0.0", - "jsprim": "1.4.1", - "sshpk": "1.13.1" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true - }, - "jsprim": { - "version": "1.4.1", - "bundled": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - }, - "dependencies": { - "extsprintf": { - "version": "1.3.0", - "bundled": true - }, - "json-schema": { - "version": "0.2.3", - "bundled": true - }, - "verror": { - "version": "1.10.0", - "bundled": true, - "requires": { - "assert-plus": "1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "1.3.0" - }, - "dependencies": { - "core-util-is": { - "version": "1.0.2", - "bundled": true - } - } - } - } - }, - "sshpk": { - "version": "1.13.1", - "bundled": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, - "dependencies": { - "asn1": { - "version": "0.2.3", - "bundled": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "bundled": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "dashdash": { - "version": "1.14.1", - "bundled": true, - "requires": { - "assert-plus": "1.0.0" - } - }, - "ecc-jsbn": { - "version": "0.1.1", - "bundled": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "getpass": { - "version": "0.1.7", - "bundled": true, - "requires": { - "assert-plus": "1.0.0" - } - }, - "jsbn": { - "version": "0.1.1", - "bundled": true, - "optional": true - }, - "tweetnacl": { - "version": "0.14.5", - "bundled": true, - "optional": true - } - } - } - } - }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true - }, - "mime-types": { - "version": "2.1.17", - "bundled": true, - "requires": { - "mime-db": "1.30.0" - }, - "dependencies": { - "mime-db": { - "version": "1.30.0", - "bundled": true - } - } - }, - "oauth-sign": { - "version": "0.8.2", - "bundled": true - }, - "performance-now": { - "version": "2.1.0", - "bundled": true - }, - "qs": { - "version": "6.5.1", - "bundled": true - }, - "stringstream": { - "version": "0.0.5", - "bundled": true - }, - "tough-cookie": { - "version": "2.3.3", - "bundled": true, - "requires": { - "punycode": "1.4.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "bundled": true - } - } - }, - "tunnel-agent": { - "version": "0.6.0", - "bundled": true, - "requires": { - "safe-buffer": "5.1.1" - } - } - } - }, - "retry": { - "version": "0.10.1", - "bundled": true - }, - "rimraf": { - "version": "2.6.2", - "bundled": true, - "requires": { - "glob": "7.1.2" - } - }, - "safe-buffer": { - "version": "5.1.1", - "bundled": true - }, - "semver": { - "version": "5.5.0", - "bundled": true - }, - "sha": { - "version": "2.0.1", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "readable-stream": "2.3.4" - } - }, - "slide": { - "version": "1.1.6", - "bundled": true - }, - "sorted-object": { - "version": "2.0.1", - "bundled": true - }, - "sorted-union-stream": { - "version": "2.1.3", - "bundled": true, - "requires": { - "from2": "1.3.0", - "stream-iterate": "1.2.0" - }, - "dependencies": { - "from2": { - "version": "1.3.0", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "1.1.14" - }, - "dependencies": { - "readable-stream": { - "version": "1.1.14", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - }, - "dependencies": { - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "isarray": { - "version": "0.0.1", - "bundled": true - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - } - } - } - } - }, - "stream-iterate": { - "version": "1.2.0", - "bundled": true, - "requires": { - "readable-stream": "2.3.4", - "stream-shift": "1.0.0" - }, - "dependencies": { - "stream-shift": { - "version": "1.0.0", - "bundled": true - } - } - } - } - }, - "ssri": { - "version": "5.2.4", - "bundled": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, - "strip-ansi": { - "version": "4.0.0", - "bundled": true, - "requires": { - "ansi-regex": "3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "bundled": true - } - } - }, - "tar": { - "version": "4.3.3", - "bundled": true, - "requires": { - "chownr": "1.0.1", - "fs-minipass": "1.2.5", - "minipass": "2.2.1", - "minizlib": "1.1.0", - "mkdirp": "0.5.1", - "yallist": "3.0.2" - }, - "dependencies": { - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "requires": { - "minipass": "2.2.1" - } - }, - "minipass": { - "version": "2.2.1", - "bundled": true, - "requires": { - "yallist": "3.0.2" - } - }, - "minizlib": { - "version": "1.1.0", - "bundled": true, - "requires": { - "minipass": "2.2.1" - } - }, - "yallist": { - "version": "3.0.2", - "bundled": true - } - } - }, - "text-table": { - "version": "0.2.0", - "bundled": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true - }, - "umask": { - "version": "1.1.0", - "bundled": true - }, - "unique-filename": { - "version": "1.1.0", - "bundled": true, - "requires": { - "unique-slug": "2.0.0" - }, - "dependencies": { - "unique-slug": { - "version": "2.0.0", - "bundled": true, - "requires": { - "imurmurhash": "0.1.4" - } - } - } - }, - "unpipe": { - "version": "1.0.0", - "bundled": true - }, - "update-notifier": { - "version": "2.3.0", - "bundled": true, - "requires": { - "boxen": "1.2.1", - "chalk": "2.1.0", - "configstore": "3.1.1", - "import-lazy": "2.1.0", - "is-installed-globally": "0.1.0", - "is-npm": "1.0.0", - "latest-version": "3.1.0", - "semver-diff": "2.1.0", - "xdg-basedir": "3.0.0" - }, - "dependencies": { - "boxen": { - "version": "1.2.1", - "bundled": true, - "requires": { - "ansi-align": "2.0.0", - "camelcase": "4.1.0", - "chalk": "2.1.0", - "cli-boxes": "1.0.0", - "string-width": "2.1.1", - "term-size": "1.2.0", - "widest-line": "1.0.0" - }, - "dependencies": { - "ansi-align": { - "version": "2.0.0", - "bundled": true, - "requires": { - "string-width": "2.1.1" - } - }, - "camelcase": { - "version": "4.1.0", - "bundled": true - }, - "cli-boxes": { - "version": "1.0.0", - "bundled": true - }, - "string-width": { - "version": "2.1.1", - "bundled": true, - "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true - } - } - }, - "term-size": { - "version": "1.2.0", - "bundled": true, - "requires": { - "execa": "0.7.0" - }, - "dependencies": { - "execa": { - "version": "0.7.0", - "bundled": true, - "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "5.1.0", - "bundled": true, - "requires": { - "lru-cache": "4.1.1", - "shebang-command": "1.2.0", - "which": "1.3.0" - }, - "dependencies": { - "shebang-command": { - "version": "1.2.0", - "bundled": true, - "requires": { - "shebang-regex": "1.0.0" - }, - "dependencies": { - "shebang-regex": { - "version": "1.0.0", - "bundled": true - } - } - } - } - }, - "get-stream": { - "version": "3.0.0", - "bundled": true - }, - "is-stream": { - "version": "1.1.0", - "bundled": true - }, - "npm-run-path": { - "version": "2.0.2", - "bundled": true, - "requires": { - "path-key": "2.0.1" - }, - "dependencies": { - "path-key": { - "version": "2.0.1", - "bundled": true - } - } - }, - "p-finally": { - "version": "1.0.0", - "bundled": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true - }, - "strip-eof": { - "version": "1.0.0", - "bundled": true - } - } - } - } - }, - "widest-line": { - "version": "1.0.0", - "bundled": true, - "requires": { - "string-width": "1.0.2" - }, - "dependencies": { - "string-width": { - "version": "1.0.2", - "bundled": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - }, - "dependencies": { - "code-point-at": { - "version": "1.1.0", - "bundled": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "requires": { - "number-is-nan": "1.0.1" - }, - "dependencies": { - "number-is-nan": { - "version": "1.0.1", - "bundled": true - } - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "bundled": true - } - } - } - } - } - } - } - } - }, - "chalk": { - "version": "2.1.0", - "bundled": true, - "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.4.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.0", - "bundled": true, - "requires": { - "color-convert": "1.9.0" - }, - "dependencies": { - "color-convert": { - "version": "1.9.0", - "bundled": true, - "requires": { - "color-name": "1.1.3" - }, - "dependencies": { - "color-name": { - "version": "1.1.3", - "bundled": true - } - } - } - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "bundled": true - }, - "supports-color": { - "version": "4.4.0", - "bundled": true, - "requires": { - "has-flag": "2.0.0" - }, - "dependencies": { - "has-flag": { - "version": "2.0.0", - "bundled": true - } - } - } - } - }, - "configstore": { - "version": "3.1.1", - "bundled": true, - "requires": { - "dot-prop": "4.2.0", - "graceful-fs": "4.1.11", - "make-dir": "1.0.0", - "unique-string": "1.0.0", - "write-file-atomic": "2.1.0", - "xdg-basedir": "3.0.0" - }, - "dependencies": { - "dot-prop": { - "version": "4.2.0", - "bundled": true, - "requires": { - "is-obj": "1.0.1" - }, - "dependencies": { - "is-obj": { - "version": "1.0.1", - "bundled": true - } - } - }, - "make-dir": { - "version": "1.0.0", - "bundled": true, - "requires": { - "pify": "2.3.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "bundled": true - } - } - }, - "unique-string": { - "version": "1.0.0", - "bundled": true, - "requires": { - "crypto-random-string": "1.0.0" - }, - "dependencies": { - "crypto-random-string": { - "version": "1.0.0", - "bundled": true - } - } - } - } - }, - "import-lazy": { - "version": "2.1.0", - "bundled": true - }, - "is-installed-globally": { - "version": "0.1.0", - "bundled": true, - "requires": { - "global-dirs": "0.1.0", - "is-path-inside": "1.0.0" - }, - "dependencies": { - "global-dirs": { - "version": "0.1.0", - "bundled": true, - "requires": { - "ini": "1.3.5" - } - }, - "is-path-inside": { - "version": "1.0.0", - "bundled": true, - "requires": { - "path-is-inside": "1.0.2" - } - } - } - }, - "is-npm": { - "version": "1.0.0", - "bundled": true - }, - "latest-version": { - "version": "3.1.0", - "bundled": true, - "requires": { - "package-json": "4.0.1" - }, - "dependencies": { - "package-json": { - "version": "4.0.1", - "bundled": true, - "requires": { - "got": "6.7.1", - "registry-auth-token": "3.3.1", - "registry-url": "3.1.0", - "semver": "5.5.0" - }, - "dependencies": { - "got": { - "version": "6.7.1", - "bundled": true, - "requires": { - "create-error-class": "3.0.2", - "duplexer3": "0.1.4", - "get-stream": "3.0.0", - "is-redirect": "1.0.0", - "is-retry-allowed": "1.1.0", - "is-stream": "1.1.0", - "lowercase-keys": "1.0.0", - "safe-buffer": "5.1.1", - "timed-out": "4.0.1", - "unzip-response": "2.0.1", - "url-parse-lax": "1.0.0" - }, - "dependencies": { - "create-error-class": { - "version": "3.0.2", - "bundled": true, - "requires": { - "capture-stack-trace": "1.0.0" - }, - "dependencies": { - "capture-stack-trace": { - "version": "1.0.0", - "bundled": true - } - } - }, - "duplexer3": { - "version": "0.1.4", - "bundled": true - }, - "get-stream": { - "version": "3.0.0", - "bundled": true - }, - "is-redirect": { - "version": "1.0.0", - "bundled": true - }, - "is-retry-allowed": { - "version": "1.1.0", - "bundled": true - }, - "is-stream": { - "version": "1.1.0", - "bundled": true - }, - "lowercase-keys": { - "version": "1.0.0", - "bundled": true - }, - "timed-out": { - "version": "4.0.1", - "bundled": true - }, - "unzip-response": { - "version": "2.0.1", - "bundled": true - }, - "url-parse-lax": { - "version": "1.0.0", - "bundled": true, - "requires": { - "prepend-http": "1.0.4" - }, - "dependencies": { - "prepend-http": { - "version": "1.0.4", - "bundled": true - } - } - } - } - }, - "registry-auth-token": { - "version": "3.3.1", - "bundled": true, - "requires": { - "rc": "1.2.1", - "safe-buffer": "5.1.1" - }, - "dependencies": { - "rc": { - "version": "1.2.1", - "bundled": true, - "requires": { - "deep-extend": "0.4.2", - "ini": "1.3.5", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" - }, - "dependencies": { - "deep-extend": { - "version": "0.4.2", - "bundled": true - }, - "minimist": { - "version": "1.2.0", - "bundled": true - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true - } - } - } - } - }, - "registry-url": { - "version": "3.1.0", - "bundled": true, - "requires": { - "rc": "1.2.1" - }, - "dependencies": { - "rc": { - "version": "1.2.1", - "bundled": true, - "requires": { - "deep-extend": "0.4.2", - "ini": "1.3.5", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" - }, - "dependencies": { - "deep-extend": { - "version": "0.4.2", - "bundled": true - }, - "minimist": { - "version": "1.2.0", - "bundled": true - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true - } - } - } - } - } - } - } - } - }, - "semver-diff": { - "version": "2.1.0", - "bundled": true, - "requires": { - "semver": "5.5.0" - } - }, - "xdg-basedir": { - "version": "3.0.0", - "bundled": true - } - } - }, - "uuid": { - "version": "3.2.1", - "bundled": true - }, - "validate-npm-package-license": { - "version": "3.0.1", - "bundled": true, - "requires": { - "spdx-correct": "1.0.2", - "spdx-expression-parse": "1.0.4" - }, - "dependencies": { - "spdx-correct": { - "version": "1.0.2", - "bundled": true, - "requires": { - "spdx-license-ids": "1.2.2" - }, - "dependencies": { - "spdx-license-ids": { - "version": "1.2.2", - "bundled": true - } - } - }, - "spdx-expression-parse": { - "version": "1.0.4", - "bundled": true - } - } - }, - "validate-npm-package-name": { - "version": "3.0.0", - "bundled": true, - "requires": { - "builtins": "1.0.3" - }, - "dependencies": { - "builtins": { - "version": "1.0.3", - "bundled": true - } - } - }, - "which": { - "version": "1.3.0", - "bundled": true, - "requires": { - "isexe": "2.0.0" - }, - "dependencies": { - "isexe": { - "version": "2.0.0", - "bundled": true - } - } - }, - "worker-farm": { - "version": "1.5.2", - "bundled": true, - "requires": { - "errno": "0.1.7", - "xtend": "4.0.1" - }, - "dependencies": { - "errno": { - "version": "0.1.7", - "bundled": true, - "requires": { - "prr": "1.0.1" - }, - "dependencies": { - "prr": { - "version": "1.0.1", - "bundled": true - } - } - }, - "xtend": { - "version": "4.0.1", - "bundled": true - } - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", + "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.10", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true }, - "write-file-atomic": { - "version": "2.1.0", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "imurmurhash": "0.1.4", - "slide": "1.1.6" - } + "vite": { + "optional": true } } }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "node_modules/@vitest/pretty-format": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", + "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", "dev": true, - "requires": { - "path-key": "2.0.1" + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "node_modules/@vitest/runner": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", + "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.10", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } }, - "os-locale": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", - "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "node_modules/@vitest/snapshot": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", + "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", "dev": true, - "requires": { - "execa": "0.7.0", - "lcid": "1.0.0", - "mem": "1.1.0" + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.10", + "@vitest/utils": "4.1.10", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true + "node_modules/@vitest/spy": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", + "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } }, - "p-limit": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", - "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", + "node_modules/@vitest/utils": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", + "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.10", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/ast-v8-to-istanbul": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.5.tgz", + "integrity": "sha512-UPAgKJFSEGMWSDr3LX4tqnAb4f7KGT8O40Tyx8wbYmmZ/yn58lNCm8h3svs3eXgiGd5AXxz8NDOvXWvicq+rJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^10.0.0" + } + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "dev": true, - "requires": { - "p-try": "1.0.0" + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "p-locate": { + "node_modules/convert-source-map": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, - "requires": { - "p-limit": "1.2.0" + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" } }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true + "node_modules/es-module-lexer": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", + "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", + "dev": true, + "license": "MIT" }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/js-tokens": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], "dev": true, - "requires": { - "shebang-regex": "1.0.0" + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "node_modules/magicast": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.4.tgz", + "integrity": "sha512-llBEhWm1SacoRwgHUoQJYtwp4PBLF4faQi5TCpIGyGs9n4y5+juI0tDgyKIfpqxckRHaHzouUEph3THklWh03w==", "dev": true, - "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "source-map-js": "^1.2.1" } }, - "strip-ansi": { + "node_modules/make-dir": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nanoid": { + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/obug": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", + "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", "dev": true, - "requires": { - "ansi-regex": "3.0.0" + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" } }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" }, - "which": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.25", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz", + "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.16", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rolldown": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.1.tgz", + "integrity": "sha512-4FKJhg8d3OiyQOA6Q1Q0hoFFpW9/OoX+VsHzpECsdsIZoOArrAK90gl59YK/Z+gnDel45bgJZK03ozH/9bCqEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.142.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.2.1", + "@rolldown/binding-darwin-arm64": "1.2.1", + "@rolldown/binding-darwin-x64": "1.2.1", + "@rolldown/binding-freebsd-x64": "1.2.1", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.1", + "@rolldown/binding-linux-arm64-gnu": "1.2.1", + "@rolldown/binding-linux-arm64-musl": "1.2.1", + "@rolldown/binding-linux-ppc64-gnu": "1.2.1", + "@rolldown/binding-linux-s390x-gnu": "1.2.1", + "@rolldown/binding-linux-x64-gnu": "1.2.1", + "@rolldown/binding-linux-x64-musl": "1.2.1", + "@rolldown/binding-openharmony-arm64": "1.2.1", + "@rolldown/binding-wasm32-wasi": "1.2.1", + "@rolldown/binding-win32-arm64-msvc": "1.2.1", + "@rolldown/binding-win32-x64-msvc": "1.2.1" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, - "requires": { - "isexe": "2.0.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "which-module": { + "node_modules/siginfo": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", + "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", + "dev": true, + "license": "MIT" }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1" + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.0.tgz", + "integrity": "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", + "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/vite": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.0.tgz", + "integrity": "sha512-pn+CFpM0lwDeKwmOq1ZaBK/9sjorZcgqxki6MbY/jPEVd9vichIlmlD4HmQ5wdP5EgqQCFRaACBxMC7uEGc6lQ==", + "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "lightningcss": "^1.33.0", + "picomatch": "^4.0.5", + "postcss": "^8.5.23", + "rolldown": "~1.2.0", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.4.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } + "sass-embedded": { + "optional": true }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } + "stylus": { + "optional": true }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true } } }, - "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", - "dev": true - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - }, - "yargs": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.0.0.tgz", - "integrity": "sha512-Rjp+lMYQOWtgqojx1dEWorjCofi1YN7AoFvYV7b1gx/7dAAeuI4kN5SZiEvr0ZmsZTOpDRcCqrpI10L31tFkBw==", + "node_modules/vitest": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.10.tgz", + "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", "dev": true, - "requires": { - "cliui": "4.0.0", - "decamelize": "1.2.0", - "find-up": "2.1.0", - "get-caller-file": "1.0.2", - "os-locale": "2.1.0", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "2.1.1", - "which-module": "2.0.0", - "y18n": "3.2.1", - "yargs-parser": "9.0.2" + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.10", + "@vitest/mocker": "4.1.10", + "@vitest/pretty-format": "4.1.10", + "@vitest/runner": "4.1.10", + "@vitest/snapshot": "4.1.10", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.10", + "@vitest/browser-preview": "4.1.10", + "@vitest/browser-webdriverio": "4.1.10", + "@vitest/coverage-istanbul": "4.1.10", + "@vitest/coverage-v8": "4.1.10", + "@vitest/ui": "4.1.10", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } } }, - "yargs-parser": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", - "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, - "requires": { - "camelcase": "4.1.0" + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" } } } diff --git a/package.json b/package.json index 3f1e2cc..c34206e 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,15 @@ "version": "1.0.4", "description": "Determines the initial memory usage of any javascript variable in NODE.JS", "main": "sizeofvar.js", + "publishConfig": { + "access": "public" + }, "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "build:ci": "echo '✓ no build step'", + "test": "node tests/run-vitest.mjs", + "test:watch": "vitest --config .configs/vitest.config.mjs", + "coverage": "node tests/run-vitest.mjs --coverage-quiet", + "ci:coverage": "npm run coverage" }, "repository": { "type": "git", @@ -26,6 +33,8 @@ }, "homepage": "https://github.com/CLDMV/sizeofvar#readme", "devDependencies": { - "yargs": "^11.0.0" + "@cldmv/vitest-runner": "^1.2.0", + "@vitest/coverage-v8": "^4.1.10", + "vitest": "^4.1.10" } } diff --git a/test/sizeofvar/test-array.js b/test/sizeofvar/test-array.js deleted file mode 100644 index dc948fc..0000000 --- a/test/sizeofvar/test-array.js +++ /dev/null @@ -1,37 +0,0 @@ - - function makestring(string_length) { - var text = []; - var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - - for (var i = 0; i < string_length; i++) { - text.push(possible.charAt(Math.floor(Math.random() * possible.length))); - } - - return text.join(''); - } - - const vars = { - x1: [], - x2: [1], - x3: [1,2], - x4: [1,2,3], - x5: [1,2,3,4], - x6: [1,2,3,4,5], - x7: [1,2,3,4,5,7], - x8: [1,2,3,4,5,7,8], - x9: [1,2,3,4,5,7,8,9], - x10: [1,2,3,4,5,7,8,9,0], - x11: ["a"], - x12: ["a","b"], - x13: ["a","b","c"], - x14: ["a","b","c","d"], - x15: ["a","b","c","d","e"], - x16: ["",makestring(8),makestring(9),makestring(16),makestring(17)], - x17: [makestring(24),makestring(8),makestring(9),makestring(16),makestring(17)], - x18: [true], - x19: [true,false], - x20: [true,false,false], - x21: [true,makestring(24),24,makestring(8),2147483647], - x22: [true,makestring(24),24,makestring(8),2147483648] - } - module.exports = vars; \ No newline at end of file diff --git a/test/sizeofvar/test-bool.js b/test/sizeofvar/test-bool.js deleted file mode 100644 index 4d727c3..0000000 --- a/test/sizeofvar/test-bool.js +++ /dev/null @@ -1,7 +0,0 @@ - - const vars = { - x1: false, - x2: true - } - - module.exports = vars; diff --git a/test/sizeofvar/test-number.js b/test/sizeofvar/test-number.js deleted file mode 100644 index 9eba5be..0000000 --- a/test/sizeofvar/test-number.js +++ /dev/null @@ -1,24 +0,0 @@ - - const vars = { - x1: 0, - x2: 1000, - x3: 1000 * 1000, - x4: 1000 * 1000 * 1000, - x5: 1000 * 1000 * 1000 * 1000, - x6: 1000 * 1000 * 1000 * 1000 * 1000, - x7: 1000 * 1000 * 1000 * 1000 * 1000 * 1000, - x8: 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000, - x9: 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000, - x10: 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000, - x11: 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000, - x12: 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000, - x13: 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000, - x14: 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000, - x15: 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000, - x16: 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000, - x17: 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000, - x18: 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000, - x19: 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000, - x20: 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 - } - module.exports = vars; diff --git a/test/sizeofvar/test-object-complex.js b/test/sizeofvar/test-object-complex.js deleted file mode 100644 index 882b8cb..0000000 --- a/test/sizeofvar/test-object-complex.js +++ /dev/null @@ -1,77 +0,0 @@ - - const vars = { - x1: { - cmd: "auth", - username:"username", - password:"testpassword" - }, - x2: { - cmd: "auth", - username:"username", - password:"testpassword", - sub: { - cmd: "auth", - username:"username", - password:"testpassword", - } - }, - x3: { - test1: true - }, - x4: { - test1: {} - }, - x5: { - test1: { - test2: '' - } - }, - x6: { - test1: { - test2: { - test3: '' - } - } - }, - x7: { - test1: { - test2: { - test3: 'abcdefgh' - } - } - }, - x8: { - test1: { - test2: { - test3: 'abcdefgh' - } - }, - test14: { - test2: { - test3: 'abcdefgh' - } - } - }, - x9: { - a: "orange", - b: "banana", - c: "apple" - }, - x10: { - a: "orange", - b: "banana", - c: "apple", - d: 0, - e: 2147483648, - f: true, - g: false, - h: [], - i: [1,2,3,4,5], - j: {}, - k: { - test1: true - }, - } - } - - module.exports = vars; diff --git a/test/sizeofvar/test-object-key-length.js b/test/sizeofvar/test-object-key-length.js deleted file mode 100644 index 9aff4ed..0000000 --- a/test/sizeofvar/test-object-key-length.js +++ /dev/null @@ -1,102 +0,0 @@ - - const vars = { - // 208 - x1: { - test1: '' - }, - // +64 - // 272 - x2: { - test1: '', - test2: '' - }, - x3: { - test1: '', - test2: '', - test3: '' - }, - x4: { - test1: '', - test2: '', - test3: '', - test4: '' - }, - // +24 - // 296 - x5: { - test1: '', - test2: '', - test3: '', - test4: '', - test5: '' - }, - x6: { - test1: '', - test2: '', - test3: '', - test4: '', - test5: '', - test6: '' - }, - x7: { - test1: '', - test2: '', - test3: '', - test4: '', - test5: '', - test6: '', - test7: '' - }, - // +24 - // 320 - x8: { - test1: '', - test2: '', - test3: '', - test4: '', - test5: '', - test6: '', - test7: '', - test8: '' - }, - x9: { - test1: '', - test2: '', - test3: '', - test4: '', - test5: '', - test6: '', - test7: '', - test8: '', - test9: '' - }, - x10: { - test1: '', - test2: '', - test3: '', - test4: '', - test5: '', - test6: '', - test7: '', - test8: '', - test9: '', - test10: '' - }, - // +24 - // 344 - x11: { - test1: '', - test2: '', - test3: '', - test4: '', - test5: '', - test6: '', - test7: '', - test8: '', - test9: '', - test10: '', - test11: '' - } - } - - module.exports = vars; diff --git a/test/sizeofvar/test-object-string.js b/test/sizeofvar/test-object-string.js deleted file mode 100644 index bfb09cf..0000000 --- a/test/sizeofvar/test-object-string.js +++ /dev/null @@ -1,49 +0,0 @@ - - function makestring(string_length) { - var text = []; - var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - - for (var i = 0; i < string_length; i++) { - text.push(possible.charAt(Math.floor(Math.random() * possible.length))); - } - - return text.join(''); - } - - const vars = { - x1: { - test: "" - }, - x2: { - test: makestring(8) - }, - x3: { - test: makestring(9) - }, - x4: { - test: makestring(16) - }, - x5: { - test: makestring(17) - }, - x6: { - test: makestring(24) - }, - x7: { - test: makestring(25) - }, - x8: { - test: makestring(32) - }, - x9: { - test: makestring(33) - }, - x10: { - test: makestring(40) - }, - x11: { - test: makestring(41) - } - } - - module.exports = vars; diff --git a/test/sizeofvar/test-object.js b/test/sizeofvar/test-object.js deleted file mode 100644 index 7406d8f..0000000 --- a/test/sizeofvar/test-object.js +++ /dev/null @@ -1,55 +0,0 @@ - - const vars = { - x1: [], - x2: {}, - x3: { - test: false - }, - x4: { - test: true - }, - x5: { - test: 0 - }, - x6: { - test: 1 - }, - x7: { - test: {} - }, - x8: { - test: [] - }, - x9: { - test: "" - }, - x10: { - test: "abcdefghij" - }, - x11: { - test: "abcdefghijklmnopqrst" - }, - x12: { - test: "abcdefghijklmnopqrstuvwxyzabcd" - }, - x13: { - test1: 1, - test2: 1 - }, - x14: { - test1: 1, - test2: 1, - test3: 1 - }, - x15: { - test1: 1, - test2: 1, - test3: 2147483647 - }, - x16: { - test1: 1, - test2: 1, - test3: 2147483648 - } - } - module.exports = vars; \ No newline at end of file diff --git a/test/sizeofvar/test-string.js b/test/sizeofvar/test-string.js deleted file mode 100644 index 6d16e92..0000000 --- a/test/sizeofvar/test-string.js +++ /dev/null @@ -1,26 +0,0 @@ - - function makestring(string_length) { - var text = []; - var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - - for (var i = 0; i < string_length; i++) { - text.push(possible.charAt(Math.floor(Math.random() * possible.length))); - } - - return text.join(''); - } - const vars = { - x1: "", - x2: makestring(8), - x3: makestring(9), - x4: makestring(16), - x5: makestring(17), - x6: makestring(24), - x7: makestring(25), - x8: makestring(32), - x9: makestring(33), - x10: makestring(40), - x11: makestring(41), - } - - module.exports = vars; \ No newline at end of file diff --git a/test/test-mem.js b/test/test-mem.js deleted file mode 100644 index 1acb2ca..0000000 --- a/test/test-mem.js +++ /dev/null @@ -1,59 +0,0 @@ - -const sizeofvar = require('../sizeofvar.js'); - -function test(obname, ob) { - console.log('=== '+obname+' ==='); - if (argv.v) { - console.log(ob); - } - var l = sizeof2(ob); - // for some reason some variables will return lower values during process.memoryUsage if ran a 2nd time. - l = sizeof2(ob); - console.log(obname+' [sizeof2]: '+l); - l = sizeofvar(ob); - console.log(obname+' [sizeofvar]: '+l); -} - -function sizeof2(o) { - // populate the memory usage so we don't end up counting that memory footprint - process.memoryUsage(); - - var tt = JSON.stringify(o); - var t = JSON.parse(tt); - - gc(); - process.memoryUsage(); - - // Wierd Shit happening here. Have to set it 4 times for some reason. The 2nd time makes sense. - // As it would create a new variable. But the last 2 make no sense. - var start_memory = process.memoryUsage().heapUsed; - start_memory = process.memoryUsage().heapUsed; - start_memory = process.memoryUsage().heapUsed; - start_memory = process.memoryUsage().heapUsed; - - t = JSON.parse(tt); - - return (process.memoryUsage().heapUsed - start_memory); -} - -const yargs = require('yargs'); -const argv = yargs - .usage('Usage: $0 [options]') - .command('test', 'Which test to run') - .example('$0 object', 'Runs the test specified') - .demandCommand(1, 'You need at least one command before moving on') - .option('verbose', { - alias: 'v', - default: false - }) - .help('h') - .alias('h', 'help') - .epilog('Copyright 2018 - Catalyzed Motivation Inc') - .argv; - -if (typeof argv._ != "undefined" && argv._ != '') { - var vars = require('./sizeofvar/test-'+argv._+'.js'); - Object.entries(vars).forEach(([key, o]) => { - test(key,o); - }); -} \ No newline at end of file diff --git a/tests/arrays.test.mjs b/tests/arrays.test.mjs new file mode 100644 index 0000000..d5db93d --- /dev/null +++ b/tests/arrays.test.mjs @@ -0,0 +1,103 @@ +/** + * @fileoverview Characterization tests for the "array" branch of sizeofvar.js. + * + * The array branch (lines 86-110): + * - base size is 184 at level 0, 32 at any nested level; + * - a flat +16 whenever the array is non-empty (regardless of level); + * - each element is pre-subtracted (144 boolean / 152 number / 136 string) + * then recursed into with `sizeofvar(element, level+1, true)` — the + * `true` for from_array is what distinguishes array elements from + * object values in the number/boolean/string branches. + * + * Detected via `Object.prototype.toString.call(x).includes('Array')`, so this + * also covers the array-vs-object type-dispatch branch (line 15). + */ +import { describe, it, expect } from "vitest"; +import sizeofvar from "../sizeofvar.js"; + +describe("sizeofvar: array, base sizes", () => { + it("empty array at level 0 sizes to 184 (no +16 for empty)", () => { + expect(sizeofvar([])).toBe(184); + }); + + it("empty array at a nested level sizes to 32", () => { + expect(sizeofvar([], 1)).toBe(32); + }); + + it("non-empty nested array adds the base plus the flat +16", () => { + expect(sizeofvar([1], 1)).toBeGreaterThan(32); + }); +}); + +describe("sizeofvar: array of a single primitive type", () => { + it("array of numbers", () => { + expect(sizeofvar([1, 2, 3])).toBe(224); + }); + + it("array of booleans", () => { + expect(sizeofvar([true, false])).toBe(216); + }); + + it("array of strings", () => { + expect(sizeofvar(["a", "bb"])).toBe(280); + }); + + it("array of large (>= 2^31) numbers", () => { + expect(sizeofvar([3000000000, 3000000000])).toBe(248); + }); +}); + +describe("sizeofvar: array, mixed types and nesting", () => { + it("array mixing boolean/number/string/array/object elements", () => { + expect(sizeofvar([1, "a", true, [1, 2], { x: 1 }])).toBe(376); + }); + + it("array of arrays (nested arrays increment level correctly)", () => { + expect(sizeofvar([[1, 2], [3, 4]])).toBe(328); + }); + + it("three levels of array nesting", () => { + expect(sizeofvar([[[1]]])).toBe(304); + }); + + it("array containing an object which itself contains an array", () => { + expect(sizeofvar([{ a: [1, 2, 3] }, { b: 4 }])).toBe(384); + }); +}); + +describe("sizeofvar: array, element types outside the boolean/number/string subtraction switch", () => { + // undefined/function/symbol/bigint elements don't match any case in the + // pre-recursion subtraction switch, and recurse to 0 (no matching type in + // the outer switch either), so they only contribute the flat array + // overhead, never a per-element adjustment. + it("array of a single undefined element", () => { + expect(sizeofvar([undefined])).toBe(200); + }); + + it("array mixing undefined/function/symbol/bigint elements", () => { + expect(sizeofvar([undefined, function () {}, Symbol("x"), 10n])).toBe(200); + }); + + it("array of Date objects (treated as plain objects with no own enumerable keys)", () => { + expect(sizeofvar([new Date(), new Date()])).toBe(312); + }); +}); + +describe("sizeofvar: array, independent formula cross-check (numbers only)", () => { + it("top-level array-of-small-numbers size matches base + 16 + 8*n", () => { + for (let i = 0; i < 100; i++) { + const n = Math.floor(Math.random() * 40); + const arr = new Array(n).fill(1); // all small numbers, net +8 each + const expected = 184 + (n > 0 ? 16 : 0) + n * 8; + expect(sizeofvar(arr)).toBe(expected); + } + }); + + it("is monotonically non-decreasing as array length increases", () => { + const lengths = [0, 1, 2, 3, 5, 10, 20]; + const sizes = lengths.map((n) => sizeofvar(new Array(n).fill(1))); + for (let i = 1; i < sizes.length; i++) { + expect(sizes[i]).toBeGreaterThanOrEqual(sizes[i - 1]); + } + }); +}); diff --git a/tests/booleans.test.mjs b/tests/booleans.test.mjs new file mode 100644 index 0000000..1ae4218 --- /dev/null +++ b/tests/booleans.test.mjs @@ -0,0 +1,48 @@ +/** + * @fileoverview Characterization tests for the "boolean" branch of sizeofvar.js. + * + * Booleans are the simplest branch: `size += 152` unconditionally, with no + * dependency on `level` or `from_array`. These tests lock that behavior and + * also cover how a boolean value nested inside an array vs. an object nets + * out once the caller's pre-recursion subtraction (144 for array elements, + * 152 for object values — see sizeofvar.js lines 62-64 and 95-96) is applied. + */ +import { describe, it, expect } from "vitest"; +import sizeofvar from "../sizeofvar.js"; + +describe("sizeofvar: boolean", () => { + it("top-level true/false both size to 152", () => { + expect(sizeofvar(true)).toBe(152); + expect(sizeofvar(false)).toBe(152); + }); + + it("ignores level and from_array entirely (always 152)", () => { + expect(sizeofvar(true, 0)).toBe(152); + expect(sizeofvar(true, 0, false)).toBe(152); + expect(sizeofvar(true, 0, true)).toBe(152); + expect(sizeofvar(true, 1)).toBe(152); + expect(sizeofvar(true, 1, false)).toBe(152); + expect(sizeofvar(true, 1, true)).toBe(152); + expect(sizeofvar(false, 5, true)).toBe(152); + }); + + it("nested as an object value nets to the object's base size (152 subtracted, 152 added back)", () => { + // {} would be 208; a single boolean value is a net-zero contribution + // because the pre-recursion subtraction (152) exactly cancels the + // boolean branch's own 152. + expect(sizeofvar({ a: true })).toBe(208); + expect(sizeofvar({ a: false })).toBe(208); + }); + + it("nested as an array element contributes +8 net (144 subtracted vs. 152 added)", () => { + // [] is 184; a 2-element boolean array demonstrates the +8-per-element + // asymmetry between the array pre-recursion subtraction (144) and the + // boolean branch's fixed 152. + expect(sizeofvar([true, false])).toBe(216); + }); + + it("nested boolean values are unaffected by recursion depth beyond level 1", () => { + expect(sizeofvar({ a: { b: true } })).toBe(sizeofvar({ a: { b: false } })); + expect(sizeofvar([[true]], 0)).toBe(sizeofvar([[false]], 0)); + }); +}); diff --git a/tests/edge-types.test.mjs b/tests/edge-types.test.mjs new file mode 100644 index 0000000..c739c23 --- /dev/null +++ b/tests/edge-types.test.mjs @@ -0,0 +1,88 @@ +/** + * @fileoverview Characterization tests for values that fall OUTSIDE the six + * handled switch cases (boolean/number/string/object/array) in sizeofvar.js, + * plus the two default-parameter branches (`level`/`from_array` omitted). + * + * `undefined`, functions, symbols, and bigints all produce a `type` string + * that matches no `case` in the switch (lines 21-111), so `size` stays at + * its initial 0 and the function returns 0 — this exercises the switch's + * implicit "no case matched" control-flow path. + * + * `null` is a special case: `typeof null === "object"` (line 11 is false), + * so it goes through `Object.prototype.toString.call(null)` -> `"[object + * Null]"`, which does NOT include "Array" (line 15), so it's dispatched to + * the "object" case. But `Object.entries(null)` (line 60) throws a + * TypeError before any size is computed — the current implementation does + * not special-case null, and this test locks that throwing behavior as-is. + */ +import { describe, it, expect } from "vitest"; +import sizeofvar from "../sizeofvar.js"; + +describe("sizeofvar: types with no matching switch case return 0", () => { + it("undefined", () => { + expect(sizeofvar(undefined)).toBe(0); + }); + + it("function", () => { + expect(sizeofvar(function () {})).toBe(0); + }); + + it("symbol", () => { + expect(sizeofvar(Symbol("x"))).toBe(0); + }); + + it("bigint", () => { + expect(sizeofvar(10n)).toBe(0); + }); + + it("calling with zero arguments (object itself undefined) also returns 0", () => { + expect(sizeofvar()).toBe(0); + }); +}); + +describe("sizeofvar: null throws instead of sizing", () => { + it("throws a TypeError from Object.entries(null)", () => { + expect(() => sizeofvar(null)).toThrow(TypeError); + expect(() => sizeofvar(null)).toThrow(/Cannot convert undefined or null to object/); + }); + + it("null nested as an object value propagates the same throw", () => { + expect(() => sizeofvar({ a: null })).toThrow(TypeError); + }); +}); + +describe("sizeofvar: unmatched-type values nested inside containers", () => { + it("undefined as the sole array element contributes only the array's flat overhead", () => { + expect(sizeofvar([undefined])).toBe(200); + }); + + it("undefined as an object value contributes nothing extra", () => { + expect(sizeofvar({ a: undefined })).toBe(208); + }); + + it("a function as an object value contributes nothing extra", () => { + expect(sizeofvar({ a: function () {} })).toBe(208); + }); + + it("mixing several unmatched-type elements in one array", () => { + expect(sizeofvar([undefined, function () {}, Symbol("x"), 10n])).toBe(200); + }); +}); + +describe("sizeofvar: default parameters (level/from_array omitted)", () => { + it("omitting level defaults it to 0, matching an explicit 0", () => { + expect(sizeofvar(5)).toBe(sizeofvar(5, 0)); + expect(sizeofvar("hi")).toBe(sizeofvar("hi", 0)); + expect(sizeofvar({ a: 1 })).toBe(sizeofvar({ a: 1 }, 0)); + expect(sizeofvar([1, 2])).toBe(sizeofvar([1, 2], 0)); + }); + + it("omitting from_array defaults it to false, matching an explicit false", () => { + expect(sizeofvar(5, 1)).toBe(sizeofvar(5, 1, false)); + expect(sizeofvar(3000000000, 2)).toBe(sizeofvar(3000000000, 2, false)); + }); + + it("top-level default-args call matches an explicit (0, false) call", () => { + expect(sizeofvar({ a: 1 }, 0, false)).toBe(sizeofvar({ a: 1 })); + }); +}); diff --git a/tests/numbers.test.mjs b/tests/numbers.test.mjs new file mode 100644 index 0000000..34d4901 --- /dev/null +++ b/tests/numbers.test.mjs @@ -0,0 +1,94 @@ +/** + * @fileoverview Characterization tests for the "number" branch of sizeofvar.js. + * + * The number branch (lines 26-42) has three independent knobs: + * - a 2^31 magnitude threshold (`bit32 = 256**4 / 2 = 2147483648`) that adds + * an "offset" (16 or 32 bytes) when the value is >= the threshold; + * - whether `level === 0` (offset stays 16) vs. `level !== 0` combined with + * `from_array` (offset becomes 32 only when level != 0 AND !from_array); + * - an unconditional +8 whenever `from_array` is truthy, regardless of level. + * + * All exact values below were captured by executing sizeofvar.js directly, so + * they lock current behavior rather than a hand-derived expectation. + */ +import { describe, it, expect } from "vitest"; +import sizeofvar from "../sizeofvar.js"; + +const BIT32 = (256 * 256 * 256 * 256) / 2; // 2147483648 + +describe("sizeofvar: number, top-level (level 0, from_array false)", () => { + it("small/typical numbers all size to 152", () => { + expect(sizeofvar(0)).toBe(152); + expect(sizeofvar(42)).toBe(152); + expect(sizeofvar(-100)).toBe(152); + }); + + it("is exactly 152 just below the 2^31 threshold and 168 at/after it", () => { + expect(BIT32).toBe(2147483648); + expect(sizeofvar(2147483647)).toBe(152); + expect(sizeofvar(2147483648)).toBe(168); + expect(sizeofvar(3000000000)).toBe(168); + }); + + it("handles NaN and +/-Infinity per the >= comparison", () => { + // NaN >= BIT32 is false in JS, so NaN takes the "small" branch. + expect(sizeofvar(NaN)).toBe(152); + // Infinity >= BIT32 is true. + expect(sizeofvar(Infinity)).toBe(168); + expect(sizeofvar(-Infinity)).toBe(152); + }); +}); + +describe("sizeofvar: number, explicit level/from_array combinations", () => { + it("level 0 with from_array=true still skips the offset bump but adds +8", () => { + // At level 0 the `if (level == 0) {}` branch is a no-op regardless of + // from_array, so offset stays 16 (irrelevant here since 5 < BIT32); + // the trailing `if (from_array) size += 8` still applies unconditionally. + expect(sizeofvar(5, 0, true)).toBe(160); + }); + + it("level !== 0 and from_array=true (typical array element): +8, offset 16", () => { + expect(sizeofvar(5, 1, true)).toBe(160); + expect(sizeofvar(3000000000, 1, true)).toBe(176); + }); + + it("level !== 0 and from_array=false (typical object value): no +8, offset 32", () => { + expect(sizeofvar(5, 1, false)).toBe(152); + expect(sizeofvar(3000000000, 1, false)).toBe(184); + }); + + it("omitting from_array at a nested level defaults it to false", () => { + expect(sizeofvar(5, 1)).toBe(sizeofvar(5, 1, false)); + expect(sizeofvar(3000000000, 1)).toBe(sizeofvar(3000000000, 1, false)); + }); +}); + +describe("sizeofvar: number, nested via container (net contribution)", () => { + it("a small number as an object value nets to 0 extra (152 subtracted, 152 added back)", () => { + expect(sizeofvar({ a: 1 })).toBe(208); + }); + + it("a large number as an object value nets +32 (offset 32 survives the subtraction)", () => { + expect(sizeofvar({ a: 3000000000 })).toBe(240); + }); + + it("a small number as an array element nets +8 (from_array's flat +8)", () => { + expect(sizeofvar([1, 2, 3])).toBe(224); + }); + + it("a large number as an array element nets +24 (offset 16 + from_array's +8)", () => { + expect(sizeofvar([3000000000, 3000000000])).toBe(248); + }); +}); + +describe("sizeofvar: number, independent formula cross-check", () => { + it("top-level size matches the 152/168 threshold formula for many random magnitudes", () => { + for (let i = 0; i < 200; i++) { + // Spread samples across a wide range straddling BIT32, including + // negatives, to exercise the >= comparison broadly. + const n = Math.floor((Math.random() - 0.3) * BIT32 * 3); + const expected = n >= BIT32 ? 168 : 152; + expect(sizeofvar(n)).toBe(expected); + } + }); +}); diff --git a/tests/objects.test.mjs b/tests/objects.test.mjs new file mode 100644 index 0000000..3a4f4f4 --- /dev/null +++ b/tests/objects.test.mjs @@ -0,0 +1,161 @@ +/** + * @fileoverview Characterization tests for the "object" branch of sizeofvar.js. + * + * The object branch (lines 52-85): + * - base size is 208 at level 0, 56 at any nested level; + * - each entry is pre-subtracted (152 boolean / 152 number / 144 string) + * then recursed into with `sizeofvar(value, level+1)` — from_array is + * omitted, so it defaults to false, which is what distinguishes object + * values from array elements in the number branch; + * - a "hash bucket" style overhead based on entry COUNT only: after the + * loop, `c` = number of entries; if `c > 0`, decrement it, and if it's + * still > 0, add `40 + ceil(c / 3) * 24`. Key NAMES (and their lengths) + * are never read (the `key` from `Object.entries` is destructured but + * unused outside a commented-out console.log) — verified explicitly + * below by a key-length-invariance assertion. + * + * Detected via `Object.prototype.toString.call(x)` NOT including 'Array', so + * this also covers the object-vs-array type-dispatch branch (line 15) for + * plain objects, Dates, RegExps, and null (which throws — see edge-types). + */ +import { describe, it, expect } from "vitest"; +import sizeofvar from "../sizeofvar.js"; + +describe("sizeofvar: object, base sizes", () => { + it("empty object at level 0 sizes to 208", () => { + expect(sizeofvar({})).toBe(208); + }); + + it("empty object at a nested level sizes to 56", () => { + expect(sizeofvar({}, 1)).toBe(56); + }); + + it("omitting level/from_array at top level matches explicitly passing 0/false", () => { + expect(sizeofvar({ a: 1 })).toBe(sizeofvar({ a: 1 }, 0, false)); + }); +}); + +describe("sizeofvar: object, single-value-type entries", () => { + it("single number entry nets to the empty-object size (152 sub, 152 add back)", () => { + expect(sizeofvar({ a: 1 })).toBe(208); + }); + + it("single boolean entry also nets to the empty-object size", () => { + expect(sizeofvar({ a: true })).toBe(208); + }); + + it("single string entry nets +32 (152 base string minus 144 sub, plus level-based extras)", () => { + expect(sizeofvar({ a: "x" })).toBe(240); + }); + + it("single large number entry nets +32 (magnitude offset survives the subtraction)", () => { + expect(sizeofvar({ a: 3000000000 })).toBe(240); + }); +}); + +describe("sizeofvar: object, entry-count overhead staircase", () => { + // c=0 -> outer `if (c > 0)` is false, no overhead. + // c=1 -> outer true, but `c -= 1` makes it 0, inner `if (c > 0)` is false. + // c=2..4 -> inner c-1 in [1,3], ceil(./3)=1 -> +40+24=+64. + // c=5..7 -> inner c-1 in [4,6], ceil(./3)=2 -> +40+48=+88. + // c=8 -> inner c-1=7, ceil(7/3)=3 -> +40+72=+112. + // All entries below are numbers, which net 0 extra per-entry, isolating + // the count-based overhead in the totals. + it("0 entries: 208 (no overhead)", () => { + expect(sizeofvar({})).toBe(208); + }); + + it("1 entry: 208 (no overhead — inner branch not reached)", () => { + expect(sizeofvar({ a: 1 })).toBe(208); + }); + + it("2, 3, and 4 entries all land in the same +64 bucket", () => { + expect(sizeofvar({ a: 1, b: 2 })).toBe(272); + expect(sizeofvar({ a: 1, b: 2, c: 3 })).toBe(272); + expect(sizeofvar({ a: 1, b: 2, c: 3, d: 4 })).toBe(272); + }); + + it("5, 6, and 7 entries all land in the same +88 bucket", () => { + expect(sizeofvar({ a: 1, b: 2, c: 3, d: 4, e: 5 })).toBe(296); + expect(sizeofvar({ a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 })).toBe(296); + expect(sizeofvar({ a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7 })).toBe(296); + }); + + it("8 entries steps up to the +112 bucket", () => { + expect(sizeofvar({ a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8 })).toBe(320); + }); +}); + +describe("sizeofvar: object, key length has NO effect on size", () => { + it("a short key name and a very long key name produce identical sizes", () => { + const shortKey = sizeofvar({ a: "hello" }); + const longKey = sizeofvar({ thisIsAVeryLongKeyNameIndeedForSure123456789: "hello" }); + expect(shortKey).toBe(240); + expect(longKey).toBe(240); + expect(shortKey).toBe(longKey); + }); + + it("holds across many random key-name lengths for an otherwise-identical value", () => { + const makeKey = (len) => + Array.from({ length: len }, () => String.fromCharCode(97 + Math.floor(Math.random() * 26))).join(""); + const baseline = sizeofvar({ [makeKey(1)]: 42 }); + for (let i = 0; i < 20; i++) { + const len = 1 + Math.floor(Math.random() * 200); + expect(sizeofvar({ [makeKey(len)]: 42 })).toBe(baseline); + } + }); +}); + +describe("sizeofvar: object, nested containers as values", () => { + it("object value nested inside an object", () => { + expect(sizeofvar({ a: { b: 1 } })).toBe(264); + }); + + it("array value nested inside an object", () => { + expect(sizeofvar({ a: [1, 2, 3] })).toBe(280); + }); + + it("three levels of object nesting", () => { + expect(sizeofvar({ a: { b: { c: 1 } } })).toBe(320); + }); + + it("object containing an array which contains objects", () => { + expect(sizeofvar({ a: [{ b: 1 }, { c: 2 }] })).toBe(368); + }); + + it("mixed-type object (number, string, boolean) at 3 and 5 entries", () => { + expect(sizeofvar({ a: 1, b: "x", c: true })).toBe(304); + expect(sizeofvar({ a: 1, b: "x", c: true, d: [1, 2], e: { f: 1 } })).toBe(448); + }); +}); + +describe("sizeofvar: object, non-plain-object values via Object.prototype.toString dispatch", () => { + it("a Date has no own enumerable keys, so it sizes like an empty object", () => { + expect(sizeofvar(new Date())).toBe(208); + }); + + it("a RegExp has no own enumerable keys, so it sizes like an empty object", () => { + expect(sizeofvar(/abc/)).toBe(208); + }); + + it("a Date nested as an object value nets to the empty-object nested overhead", () => { + expect(sizeofvar({ a: new Date() })).toBe(264); + }); +}); + +describe("sizeofvar: object, independent formula cross-check (numbers-only values)", () => { + it("size matches base(208) + count-overhead(c) for many random entry counts", () => { + const overhead = (c) => { + if (c <= 0) return 0; + const rest = c - 1; + if (rest <= 0) return 0; + return 40 + Math.ceil(rest / 3) * 24; + }; + for (let i = 0; i < 60; i++) { + const c = Math.floor(Math.random() * 30); + const obj = {}; + for (let k = 0; k < c; k++) obj["k" + k] = k; + expect(sizeofvar(obj)).toBe(208 + overhead(c)); + } + }); +}); diff --git a/tests/random-properties.test.mjs b/tests/random-properties.test.mjs new file mode 100644 index 0000000..feb7150 --- /dev/null +++ b/tests/random-properties.test.mjs @@ -0,0 +1,154 @@ +/** + * @fileoverview Property-based tests for sizeofvar.js using randomized + * inputs, asserting stable INVARIANTS (type consistency, monotonicity, + * threshold behavior) rather than a single locked byte count. Complements + * the exact-value characterization tests in the other files, which cover + * deterministic inputs. + */ +import { describe, it, expect } from "vitest"; +import sizeofvar from "../sizeofvar.js"; + +const BIT32 = (256 * 256 * 256 * 256) / 2; // 2147483648 + +function randomString(maxLen) { + const len = Math.floor(Math.random() * maxLen); + let s = ""; + for (let i = 0; i < len; i++) { + s += String.fromCharCode(32 + Math.floor(Math.random() * 95)); + } + return s; +} + +describe("sizeofvar: random-input type consistency", () => { + it("always returns a finite number for random booleans", () => { + for (let i = 0; i < 50; i++) { + const v = Math.random() < 0.5; + const result = sizeofvar(v); + expect(typeof result).toBe("number"); + expect(Number.isFinite(result)).toBe(true); + expect(result).toBe(152); + } + }); + + it("always returns a finite number for random top-level numbers", () => { + for (let i = 0; i < 50; i++) { + const v = (Math.random() - 0.5) * Number.MAX_SAFE_INTEGER; + const result = sizeofvar(v); + expect(typeof result).toBe("number"); + expect(Number.isFinite(result)).toBe(true); + } + }); + + it("always returns a finite number for random strings", () => { + for (let i = 0; i < 50; i++) { + const result = sizeofvar(randomString(80)); + expect(typeof result).toBe("number"); + expect(Number.isFinite(result)).toBe(true); + } + }); + + it("always returns a finite number for random flat arrays of mixed primitives", () => { + const pool = [true, false, 1, -1, 3000000000, "a", "hello world", "", 0]; + for (let i = 0; i < 50; i++) { + const len = Math.floor(Math.random() * 10); + const arr = Array.from({ length: len }, () => pool[Math.floor(Math.random() * pool.length)]); + const result = sizeofvar(arr); + expect(typeof result).toBe("number"); + expect(Number.isFinite(result)).toBe(true); + } + }); + + it("always returns a finite number for random flat objects of mixed primitives", () => { + const pool = [true, false, 1, -1, 3000000000, "a", "hello world", "", 0]; + for (let i = 0; i < 50; i++) { + const count = Math.floor(Math.random() * 10); + const obj = {}; + for (let k = 0; k < count; k++) { + obj["key" + k] = pool[Math.floor(Math.random() * pool.length)]; + } + const result = sizeofvar(obj); + expect(typeof result).toBe("number"); + expect(Number.isFinite(result)).toBe(true); + } + }); +}); + +describe("sizeofvar: random-input threshold and monotonicity properties", () => { + it("top-level number result is 168 iff the value is >= 2^31, else 152", () => { + for (let i = 0; i < 200; i++) { + const n = (Math.random() - 0.3) * BIT32 * 3; + const result = sizeofvar(n); + expect(result).toBe(n >= BIT32 ? 168 : 152); + } + }); + + it("string size is monotonically non-decreasing as random length increases", () => { + const lengths = Array.from({ length: 15 }, () => Math.floor(Math.random() * 500)).sort((a, b) => a - b); + const sizes = lengths.map((n) => sizeofvar("x".repeat(n))); + for (let i = 1; i < sizes.length; i++) { + expect(sizes[i]).toBeGreaterThanOrEqual(sizes[i - 1]); + } + }); + + it("array-of-numbers size is monotonically non-decreasing as random length increases", () => { + const lengths = Array.from({ length: 15 }, () => Math.floor(Math.random() * 100)).sort((a, b) => a - b); + const sizes = lengths.map((n) => sizeofvar(new Array(n).fill(7))); + for (let i = 1; i < sizes.length; i++) { + expect(sizes[i]).toBeGreaterThanOrEqual(sizes[i - 1]); + } + }); + + it("object-of-numbers size is monotonically non-decreasing as random entry count increases", () => { + const counts = Array.from({ length: 15 }, () => Math.floor(Math.random() * 40)).sort((a, b) => a - b); + const sizes = counts.map((c) => { + const obj = {}; + for (let k = 0; k < c; k++) obj["k" + k] = k; + return sizeofvar(obj); + }); + for (let i = 1; i < sizes.length; i++) { + expect(sizes[i]).toBeGreaterThanOrEqual(sizes[i - 1]); + } + }); + + it("deterministic: calling twice with the same random input yields the same result", () => { + for (let i = 0; i < 20; i++) { + const s = randomString(50); + expect(sizeofvar(s)).toBe(sizeofvar(s)); + const n = Math.random() * Number.MAX_SAFE_INTEGER; + expect(sizeofvar(n)).toBe(sizeofvar(n)); + } + }); +}); + +describe("sizeofvar: random recursive/nested structures don't throw and stay finite", () => { + function randomLeaf() { + const pool = [true, false, 1, -1, 3000000000, "x", "", 0, undefined]; + return pool[Math.floor(Math.random() * pool.length)]; + } + + function randomTree(depth) { + if (depth <= 0) return randomLeaf(); + const kind = Math.floor(Math.random() * 3); + if (kind === 0) return randomLeaf(); + if (kind === 1) { + const len = Math.floor(Math.random() * 4); + return Array.from({ length: len }, () => randomTree(depth - 1)); + } + const count = Math.floor(Math.random() * 4); + const obj = {}; + for (let k = 0; k < count; k++) obj["k" + k] = randomTree(depth - 1); + return obj; + } + + it("random nested structures up to depth 4 always produce a finite number", () => { + for (let i = 0; i < 30; i++) { + const tree = randomTree(4); + let result; + expect(() => { + result = sizeofvar(tree); + }).not.toThrow(); + expect(typeof result).toBe("number"); + expect(Number.isFinite(result)).toBe(true); + } + }); +}); diff --git a/tests/run-vitest.mjs b/tests/run-vitest.mjs new file mode 100644 index 0000000..72f2c33 --- /dev/null +++ b/tests/run-vitest.mjs @@ -0,0 +1,51 @@ +/** + * @fileoverview OOM-safe Vitest runner for sizeofvar — delegates to + * @cldmv/vitest-runner, which spawns each test file in its own child process and + * (under coverage) uses a blob-per-file + `--mergeReports` strategy so a single + * process never holds coverage data for the whole suite. + * + * Usage: + * node tests/run-vitest.mjs # run all tests + * node tests/run-vitest.mjs --coverage # with coverage (verbose) + * node tests/run-vitest.mjs --coverage-quiet # with coverage (progress bar + summary) + * node tests/run-vitest.mjs # filter by path/name + * + * Args before a `--` delimiter are forwarded to Vitest; args after it are test + * patterns. A value-taking flag needs the delimiter, e.g.: + * node tests/run-vitest.mjs --reporter verbose -- + */ +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { run } from "@cldmv/vitest-runner"; + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const argv = process.argv.slice(2); + +// A `--` delimiter separates forwarded Vitest args (before it) from test patterns +// (after it). Without a `--`, the legacy heuristic applies: non-flag tokens are +// test patterns and flag tokens are forwarded to vitest. +const delimiter = argv.indexOf("--"); +const forwarded = delimiter === -1 ? argv.filter((a) => a.startsWith("-")) : argv.slice(0, delimiter); +const testPatterns = delimiter === -1 ? argv.filter((a) => !a.startsWith("-")) : argv.slice(delimiter + 1); + +const coverageQuiet = forwarded.includes("--coverage-quiet"); +const coverage = coverageQuiet || forwarded.includes("--coverage"); +const passthrough = forwarded.filter((a) => a !== "--coverage" && a !== "--coverage-quiet"); + +// VITEST_WORKERS overrides the worker count; ignore an unset / invalid / non-positive value. +const parsedWorkers = parseInt(process.env.VITEST_WORKERS ?? "", 10); +const workers = Number.isInteger(parsedWorkers) && parsedWorkers > 0 ? parsedWorkers : 4; + +const code = await run({ + cwd: root, + testDir: "tests", + vitestConfig: ".configs/vitest.config.mjs", + // Plain `*.test.mjs` convention. + testFilePattern: /\.test\.mjs$/, + testPatterns, + workers, + coverageQuiet, + vitestArgs: [...(coverage ? ["--coverage"] : []), ...passthrough], + nodeEnv: process.env.NODE_ENV || "development" +}); +process.exit(code); diff --git a/tests/strings.test.mjs b/tests/strings.test.mjs new file mode 100644 index 0000000..1f53c51 --- /dev/null +++ b/tests/strings.test.mjs @@ -0,0 +1,79 @@ +/** + * @fileoverview Characterization tests for the "string" branch of sizeofvar.js. + * + * The string branch (lines 43-51) is: + * size = 144 + * + (level === 0 ? 8 : 0) + * + (length > 0 ? 24 : 0) + * + ceil(length / 8) * 8 + * + * Notably this branch does NOT read `from_array` at all — only `level` + * matters for the +8 term. That asymmetry is verified explicitly below. + */ +import { describe, it, expect } from "vitest"; +import sizeofvar from "../sizeofvar.js"; + +describe("sizeofvar: string, top-level (level 0)", () => { + it("empty string sizes to 152", () => { + expect(sizeofvar("")).toBe(152); + }); + + it("steps every 8 characters via ceil(length / 8) * 8", () => { + expect(sizeofvar("a")).toBe(184); // length 1 -> ceil(1/8)=1 + expect(sizeofvar("12345678")).toBe(184); // length 8 -> ceil(8/8)=1, same bucket + expect(sizeofvar("123456789")).toBe(192); // length 9 -> ceil(9/8)=2, next bucket + }); +}); + +describe("sizeofvar: string, nested (level !== 0) — from_array has no effect", () => { + it("drops the level-0 +8 term regardless of from_array", () => { + expect(sizeofvar("", 1)).toBe(144); + expect(sizeofvar("", 1, true)).toBe(144); + expect(sizeofvar("", 1, false)).toBe(144); + }); + + it("non-empty nested string is identical whether from_array is true or false", () => { + expect(sizeofvar("a", 1, true)).toBe(176); + expect(sizeofvar("a", 1, false)).toBe(176); + expect(sizeofvar("a", 1)).toBe(176); + }); +}); + +describe("sizeofvar: string, nested via container (net contribution)", () => { + it("empty string as an object value nets to 0 extra (144 subtracted, 144 added back)", () => { + expect(sizeofvar({ a: "" })).toBe(208); + }); + + it("non-empty string as an object value nets +32", () => { + expect(sizeofvar({ a: "hello" })).toBe(240); + }); + + it("empty string as an array element nets +24 (136 subtracted vs. 144 added, plus the array's own +16 for being non-empty)", () => { + expect(sizeofvar([""])).toBe(208); + }); + + it("multiple non-empty strings in an array each contribute independently", () => { + // "a" (len 1) and "bb" (len 2) both fall in the same ceil(len/8)=1 + // bucket, so each contributes the same net amount. + expect(sizeofvar(["a", "bb"])).toBe(280); + }); +}); + +describe("sizeofvar: string, independent formula cross-check", () => { + it("top-level size matches the length-bucket formula for many random lengths", () => { + for (let i = 0; i < 150; i++) { + const len = Math.floor(Math.random() * 200); + const str = "x".repeat(len); + const expected = 144 + 8 + (len > 0 ? 24 : 0) + Math.ceil(len / 8) * 8; + expect(sizeofvar(str)).toBe(expected); + } + }); + + it("is monotonically non-decreasing as string length increases", () => { + const lengths = [0, 1, 2, 7, 8, 9, 15, 16, 17, 63, 64, 65, 100]; + const sizes = lengths.map((n) => sizeofvar("x".repeat(n))); + for (let i = 1; i < sizes.length; i++) { + expect(sizes[i]).toBeGreaterThanOrEqual(sizes[i - 1]); + } + }); +});