diff --git a/.clippy.toml b/.clippy.toml new file mode 100644 index 0000000..995cf22 --- /dev/null +++ b/.clippy.toml @@ -0,0 +1,12 @@ +# Enforce “small functions” (Clean Code: 5–25 lines, allow a bit for Rust formatting) +too-many-lines-threshold = 30 + +# Enforce “2–3 params typical; 4+ suggests a data object” (Clean Code) +too-many-arguments-threshold = 4 + +# Complexity guardrail (closest analogue TS complexity/max-depth posture) +cognitive-complexity-threshold = 8 + +# Optional: approximate “max nesting depth 1–2” +# Note: this is structural nesting +excessive-nesting-threshold = 3 diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..18fae85 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ + + +text +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.rs] +indent_size = 4 + +[*.md] +trim_trailing_whitespace = false + +[Makefile] +indent_style = tab \ No newline at end of file diff --git a/.github/actions/conventional-pr/action.yml b/.github/actions/conventional-pr/action.yml new file mode 100644 index 0000000..1b24ae7 --- /dev/null +++ b/.github/actions/conventional-pr/action.yml @@ -0,0 +1,62 @@ +# .github/actions/validate-pr-title/action.yml +# +# Usage: +# - uses: actions/checkout@v4 +# - uses: ./.github/actions/validate-pr-title +# with: +# github-token: ${{ secrets.GITHUB_TOKEN }} +# +# Usage (with extra scopes): +# - uses: ./.github/actions/validate-pr-title +# with: +# github-token: ${{ secrets.GITHUB_TOKEN }} +# extra-scopes: "infra,release" +# +# Scopes auto-discovered from .moon/workspace.yml projects list. +# deps, ci, repo are always included. + +name: "Validate PR Title" +description: "Enforce conventional commit format on PR titles with auto-discovered scopes" + +inputs: + github-token: + required: true + description: "GITHUB_TOKEN" + extra-scopes: + required: false + default: "" + description: "Comma-separated additional scopes beyond project names and builtins" + +runs: + using: composite + steps: + - name: Discover project scopes + id: scopes + shell: bash + run: | + projects=$(yq '.workspace.projects // .projects | + if type == "!!seq" then .[] else keys[] end' .moon/workspace.yml 2>/dev/null | sort -u) + + builtins="deps,ci,repo" + extra="${{ inputs.extra-scopes }}" + combined="${builtins}${extra:+,$extra}" + + all_scopes=$(printf "%s\n%s" "$projects" "$(echo "$combined" | tr ',' '\n')" | sort -u) + + echo "scopes<> "$GITHUB_OUTPUT" + echo "$all_scopes" >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" + + - uses: amannn/action-semantic-pull-request@v5 + env: + GITHUB_TOKEN: ${{ inputs.github-token }} + with: + types: | + feat + fix + chore + docs + refactor + test + perf + scopes: ${{ steps.scopes.outputs.scopes }} diff --git a/.github/actions/moon-ci-matrix/action.yml b/.github/actions/moon-ci-matrix/action.yml new file mode 100644 index 0000000..576c222 --- /dev/null +++ b/.github/actions/moon-ci-matrix/action.yml @@ -0,0 +1,40 @@ +name: "Moon CI Runner Matrix" +description: "Calculates optimal runner count from affected Moon tasks" + +inputs: + tasks-per-runner: + required: false + default: "3" + description: "Number of affected tasks to assign per runner" + max-parallel: + required: false + default: "6" + description: "Maximum number of concurrent runners" + +outputs: + matrix: + description: "JSON array of shard indices, e.g. [0, 1, 2]" + value: ${{ steps.calc.outputs.matrix }} + count: + description: "Total number of runners" + value: ${{ steps.calc.outputs.total }} + +runs: + using: composite + steps: + - id: calc + shell: bash + run: | + TASKS_PER_RUNNER=${{ inputs.tasks-per-runner }} + MAX_RUNNERS=${{ inputs.max-parallel }} + + TASK_COUNT=$(moon query tasks --affected | jq '[.tasks[][] | select(.options.runInCI != false)] | length') + + WANTED=$(( (TASK_COUNT + TASKS_PER_RUNNER - 1) / TASKS_PER_RUNNER )) + TOTAL=$(( WANTED > MAX_RUNNERS ? MAX_RUNNERS : WANTED )) + + MATRIX_JSON=$(jq -n -c --argjson n "$TOTAL" '[range($n)]') + + echo "Affected CI tasks: $TASK_COUNT, Runners: $TOTAL" + echo "count=$TOTAL" >> $GITHUB_OUTPUT + echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT diff --git a/.github/actions/moon-ci/action.yml b/.github/actions/moon-ci/action.yml new file mode 100644 index 0000000..b88b15b --- /dev/null +++ b/.github/actions/moon-ci/action.yml @@ -0,0 +1,32 @@ +# .github/actions/moon-ci/action.yml +# +# Usage: +# - uses: ./.github/actions/moon-ci +# with: +# access-token: ${{ secrets.GITHUB_TOKEN }} + +name: "Moon CI" +description: "Run moon ci with sharding, reporting, and retrospect" + +inputs: + access-token: + required: true + description: "GITHUB_TOKEN for run report" + +runs: + using: composite + steps: + - name: Moon CI + shell: bash + run: | + echo "Runner ${{ strategy.job-index }} of ${{ strategy.job-total }}" + moon ci --color --job ${{ strategy.job-index }} --job-total ${{ strategy.job-total }} + + - uses: moonrepo/run-report-action@v1 + if: success() || failure() + with: + access-token: ${{ inputs.access-token }} + matrix: '{"index": ${{ strategy.job-index }}, "total": ${{ strategy.job-total }}}' + + - uses: appthrust/moon-ci-retrospect@v1 + if: success() || failure() diff --git a/.github/actions/moon-raa/action.yml b/.github/actions/moon-raa/action.yml new file mode 100644 index 0000000..864e3b0 --- /dev/null +++ b/.github/actions/moon-raa/action.yml @@ -0,0 +1,57 @@ +name: "moon-raa" +description: "Manage review apps and artifacts for a Moon monorepo" + +inputs: + command: + required: true + description: "'run' or 'rm'" + pr-number: + required: true + description: "PR number" + prefix: + required: false + default: "raa" + description: "Environment name prefix (prepended to '-pr-{number}')" + github-token: + required: true + description: "GITHUB_TOKEN" + +outputs: + deployment-id: + description: "GitHub Deployment ID (run only)" + value: ${{ steps.raa.outputs.deployment-id }} + environment: + description: "Environment name" + value: ${{ steps.raa.outputs.environment }} + project-count: + description: "Number of projects processed" + value: ${{ steps.raa.outputs.project-count }} + summary: + description: "Markdown summary for GITHUB_STEP_SUMMARY" + value: ${{ steps.raa.outputs.summary }} + manifest: + description: "Full payload as JSON" + value: ${{ steps.raa.outputs.manifest }} + clean: + description: "true if rm completed without warnings (rm only)" + value: ${{ steps.raa.outputs.clean }} + +runs: + using: composite + steps: + - name: moon-raa + id: raa + uses: actions/github-script@v7 + env: + INPUT_COMMAND: ${{ inputs.command }} + INPUT_PR_NUMBER: ${{ inputs.pr-number }} + INPUT_PREFIX: ${{ inputs.prefix }} + with: + github-token: ${{ inputs.github-token }} + script: | + const cmd = process.env.INPUT_COMMAND; + const handler = require(`${{ github.action_path }}/${cmd}.js`); + await handler({ github, context, core, exec, inputs: { + pr_number: process.env.INPUT_PR_NUMBER, + prefix: process.env.INPUT_PREFIX, + }}); diff --git a/.github/actions/moon-raa/lib.js b/.github/actions/moon-raa/lib.js new file mode 100644 index 0000000..a8ac0e2 --- /dev/null +++ b/.github/actions/moon-raa/lib.js @@ -0,0 +1,139 @@ +const environmentName = (prefix, prNumber) => `${prefix}-pr-${prNumber}` + +const artifactName = (prefix, projectId, prNumber) => `${prefix}-${projectId}-pr-${prNumber}` + +const targetName = (projectId, task) => `${projectId}:${task}` + +const buildManifest = (prNumber, projects) => ({ pr_number: prNumber, projects }) + +const buildProjectEntry = (prefix, prNumber) => project => ({ + id: project.id, + artifact_name: artifactName(prefix, project.id, prNumber), + run: project.raa.run, + rm: project.raa.rm, +}) + +const validateProject = project => { + const raa = project.raa + const missing = [!raa && 'raa metadata', raa && !raa.run && 'raa.run', raa && !raa.rm && 'raa.rm'].filter( + Boolean, + ) + + return missing.length ? { valid: false, reason: `missing ${missing.join(', ')}` } : { valid: true } +} + +const partitionProjects = (projects, core) => { + const valid = [] + for (const project of projects) { + const result = validateProject(project) + if (!result.valid) { + core.warning(`Skipping ${project.id}: ${result.reason}`) + continue + } + valid.push(project) + } + return valid +} + +const formatRunSummary = (environment, projects) => { + if (!projects.length) return 'No RAA projects affected.' + + const rows = projects.map(p => `| ${p.id} | \`${p.run}\` | \`${p.artifact_name}\` |`).join('\n') + + return [ + `### RAA Review`, + '', + '| Project | Task | Artifact |', + '|---------|------|----------|', + rows, + '', + `${projects.length} project(s) deployed to \`${environment}\``, + ].join('\n') +} + +const formatRmSummary = (environment, results) => { + if (!results.length) return 'No RAA projects to tear down.' + + const rows = results.map(r => `| ${r.id} | \`${r.rm}\` | ${r.status} |`).join('\n') + + return [ + `### RAA Teardown`, + '', + '| Project | Task | Status |', + '|---------|------|--------|', + rows, + '', + `${results.length} project(s) torn down from \`${environment}\``, + ].join('\n') +} + +const listDeployments = async (github, owner, repo, environment) => { + const { data } = await github.rest.repos.listDeployments({ owner, repo, environment }) + return data +} + +const deactivateDeployments = async (github, owner, repo, environment, core) => { + const deployments = await listDeployments(github, owner, repo, environment) + + for (const deployment of deployments) { + await github.rest.repos.createDeploymentStatus({ + owner, + repo, + deployment_id: deployment.id, + state: 'inactive', + }) + await github.rest.repos.deleteDeployment({ owner, repo, deployment_id: deployment.id }) + core.info(`Deactivated and deleted deployment ${deployment.id}`) + } + + return deployments +} + +const createDeployment = async (github, owner, repo, { ref, environment, description, payload }) => { + const { data: deployment } = await github.rest.repos.createDeployment({ + owner, + repo, + ref, + environment, + auto_merge: false, + required_contexts: [], + description, + payload: JSON.stringify(payload), + }) + return deployment +} + +const setDeploymentStatus = async (github, owner, repo, deploymentId, state, description) => { + await github.rest.repos.createDeploymentStatus({ + owner, + repo, + deployment_id: deploymentId, + state, + description: description ?? '', + }) +} + +const deleteEnvironment = async (github, owner, repo, environment) => { + try { + await github.rest.repos.deleteAnEnvironment({ owner, repo, environment_name: environment }) + } catch (error) { + if (error.status !== 404) throw error + } +} + +module.exports = { + environmentName, + artifactName, + targetName, + buildManifest, + buildProjectEntry, + validateProject, + partitionProjects, + formatRunSummary, + formatRmSummary, + listDeployments, + deactivateDeployments, + createDeployment, + setDeploymentStatus, + deleteEnvironment, +} diff --git a/.github/actions/moon-raa/rm.js b/.github/actions/moon-raa/rm.js new file mode 100644 index 0000000..c1a1b60 --- /dev/null +++ b/.github/actions/moon-raa/rm.js @@ -0,0 +1,80 @@ +const { execSync } = require('child_process') +const lib = require('./lib') + +const collectTargets = deployments => + deployments.map(d => JSON.parse(d.payload || '{}')).flatMap(p => p.projects ?? []).map(( + { id, rm, artifact_name }, + ) => ({ id, rm, artifact_name })) + +const checkAffectedMismatch = (targets, core) => { + let raw + try { + raw = execSync('moon query projects --affected').toString() + } catch (error) { + core.warning(`Could not check affected projects: ${error.message}`) + return false + } + + const { projects } = JSON.parse(raw) + const affectedIds = new Set(projects.map(p => p.id)) + const stale = targets.filter(t => !affectedIds.has(t.id)) + + if (!stale.length) return true + + core.warning(`Teardown targets not in --affected: ${stale.map(t => t.id).join(', ')}`) + return false +} + +const runTeardowns = async (exec, core, targets) => { + const results = [] + for (const target of targets) { + const moonTarget = lib.targetName(target.id, target.rm) + core.info(`Running teardown: ${moonTarget}`) + try { + await exec.exec('moon', ['run', moonTarget]) + results.push({ ...target, status: 'done' }) + } catch (error) { + core.error(`Failed ${moonTarget}: ${error.message}`) + results.push({ ...target, status: 'failed' }) + } + } + return results +} + +module.exports = async ({ github, context, core, exec, inputs }) => { + const { owner, repo } = context.repo + const { pr_number, prefix } = inputs + const environment = lib.environmentName(prefix, pr_number) + + const deployments = await lib.listDeployments(github, owner, repo, environment) + + if (!deployments.length) { + core.info(`No deployments found for ${environment}`) + core.setOutput('environment', environment) + core.setOutput('project-count', '0') + core.setOutput('summary', 'No RAA projects to tear down.') + core.setOutput('manifest', '{}') + core.setOutput('clean', 'true') + return + } + + const targets = collectTargets(deployments) + const affectedClean = checkAffectedMismatch(targets, core) + const results = await runTeardowns(exec, core, targets) + + await lib.deactivateDeployments(github, owner, repo, environment, core) + await lib.deleteEnvironment(github, owner, repo, environment) + core.info(`Cleaned up environment ${environment}`) + + const manifest = { pr_number, projects: targets } + const summary = lib.formatRmSummary(environment, results) + const allPassed = results.every(r => r.status === 'done') + + core.setOutput('environment', environment) + core.setOutput('project-count', String(targets.length)) + core.setOutput('summary', summary) + core.setOutput('manifest', JSON.stringify(manifest)) + core.setOutput('clean', String(affectedClean && allPassed)) + + if (!allPassed) core.setFailed('One or more teardown tasks failed') +} diff --git a/.github/actions/moon-raa/run.js b/.github/actions/moon-raa/run.js new file mode 100644 index 0000000..77c2898 --- /dev/null +++ b/.github/actions/moon-raa/run.js @@ -0,0 +1,84 @@ +const { execSync } = require('child_process') +const lib = require('./lib') + +const discoverProjects = core => { + const { projects } = JSON.parse(execSync('moon query projects --affected').toString()) + + const withRaa = projects.filter(p => p.config?.project?.metadata?.raa).map(p => ({ + id: p.id, + raa: p.config.project.metadata.raa, + })) + + return lib.partitionProjects(withRaa, core) +} + +const runTasks = async (exec, core, projectEntries) => { + const results = [] + for (const project of projectEntries) { + const target = lib.targetName(project.id, project.run) + core.info(`Running ${target}`) + try { + await exec.exec('moon', ['run', target]) + results.push({ ...project, status: 'done' }) + } catch (error) { + core.error(`Failed ${target}: ${error.message}`) + results.push({ ...project, status: 'failed' }) + } + } + return results +} + +module.exports = async ({ github, context, core, exec, inputs }) => { + const { owner, repo } = context.repo + const { pr_number, prefix } = inputs + const environment = lib.environmentName(prefix, pr_number) + + const valid = discoverProjects(core) + + if (!valid.length) { + core.info('No affected projects with valid raa metadata') + core.setOutput('deployment-id', '') + core.setOutput('environment', environment) + core.setOutput('project-count', '0') + core.setOutput('summary', 'No RAA projects affected.') + core.setOutput('manifest', '{}') + return + } + + const projectEntries = valid.map(lib.buildProjectEntry(prefix, pr_number)) + const manifest = lib.buildManifest(pr_number, projectEntries) + + await lib.deactivateDeployments(github, owner, repo, environment, core) + + const deployment = await lib.createDeployment(github, owner, repo, { + ref: context.sha, + environment, + description: `Review for PR #${pr_number} (${valid.length} projects)`, + payload: manifest, + }) + + await lib.setDeploymentStatus( + github, + owner, + repo, + deployment.id, + 'in_progress', + 'Building review environment...', + ) + + const results = await runTasks(exec, core, projectEntries) + const allPassed = results.every(r => r.status === 'done') + + const state = allPassed ? 'success' : 'failure' + const description = allPassed ? 'Review build complete' : 'Review build failed' + await lib.setDeploymentStatus(github, owner, repo, deployment.id, state, description) + + const summary = lib.formatRunSummary(environment, results) + core.setOutput('deployment-id', String(deployment.id)) + core.setOutput('environment', environment) + core.setOutput('project-count', String(projectEntries.length)) + core.setOutput('summary', summary) + core.setOutput('manifest', JSON.stringify(manifest)) + + if (!allPassed) core.setFailed('One or more RAA tasks failed') +} diff --git a/.github/actions/moon-run/action.yml b/.github/actions/moon-run/action.yml new file mode 100644 index 0000000..35b2982 --- /dev/null +++ b/.github/actions/moon-run/action.yml @@ -0,0 +1,51 @@ +# .github/actions/moon-run/action.yml +# +# Usage (affected against remote): +# - uses: ./.github/actions/moon-run +# with: +# task: ":lint" +# affected: "remote" +# +# Usage (no affected, exact task): +# - uses: ./.github/actions/moon-run +# with: +# task: "slash-rust:publish" +# +# Usage (multiple tasks): +# - uses: ./.github/actions/moon-run +# with: +# task: ":lint :test :fmt-check" +# affected: "remote" + +name: "Moon Run" +description: "Run a moon task with standard defaults and retrospect" + +inputs: + task: + required: true + description: "Moon task(s) to run (e.g., ':lint' or 'riff-cli:publish')" + affected: + required: false + default: "" + description: "'remote' = compare against remote tracking branch, 'true' = compare against default branch, '' = no affected filtering" + +runs: + using: composite + steps: + - name: Moon Run + shell: bash + run: | + affected_flag="" + if [ "${{ inputs.affected }}" = "remote" ]; then + affected_flag="--affected remote" + elif [ "${{ inputs.affected }}" = "true" ]; then + affected_flag="--affected" + fi + moon run --color ${{ inputs.task }} $affected_flag + + - uses: appthrust/moon-ci-retrospect@v1 + if: success() || failure() + + - run: echo "${{ steps.raa.outputs.summary }}" >> $GITHUB_STEP_SUMMARY + shell: bash + if: always() diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml new file mode 100644 index 0000000..a0a73de --- /dev/null +++ b/.github/actions/setup/action.yml @@ -0,0 +1,61 @@ +# .github/actions/setup/action.yml +# +# Usage: +# - uses: ./.github/actions/setup +# with: +# cache-cargo: "true" +# cache-pnpm: "flase" +# +# Usage (minimal, no project caches): +# - uses: ./.github/actions/setup + +name: "Setup" +description: "Checkout, setup Moon/proto (lazy install), restore caches" + +inputs: + fetch-depth: + default: "0" + description: "Git fetch depth (0 for full history, needed for moon ci affected detection)" + cache-cargo: + default: "true" + description: "Restore Cargo registry, git, and target caches" + cache-pnpm: + default: "true" + description: "Restore pnpm store cache" + +runs: + using: composite + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: ${{ inputs.fetch-depth }} + + - uses: moonrepo/setup-toolchain@v0 + with: + auto-install: true + + - uses: actions/cache@v4 + with: + path: .moon/cache + key: moon-${{ runner.os }}-${{ hashFiles('.moon/workspace.yml', '.moon/tasks/*.yml', '.moon/toolchains.yml') }} + restore-keys: | + moon-${{ runner.os }}- + + - uses: actions/cache@v4 + if: inputs.cache-cargo == 'true' + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: cargo-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + cargo-${{ runner.os }}- + + - uses: actions/cache@v4 + if: inputs.cache-pnpm == 'true' + with: + path: ~/.local/share/pnpm/store + key: pnpm-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + pnpm-${{ runner.os }}- diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..a9ac0a8 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,108 @@ +name: Trunk Pipeline + +on: + push: + branches: [main] + +concurrency: + group: trunk-${{ github.sha }} + cancel-in-progress: false + +jobs: + config: + name: CI Strategy + runs-on: ubuntu-latest + outputs: + ci-matrix: ${{ steps.ci-matrix.outputs.matrix }} + runner-count: ${{ steps.ci-matrix.outputs.count }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: ./.github/actions/setup + - id: ci-matrix + uses: ./.github/actions/moon-ci-matrix + + ci: + name: Moon CI + needs: [config] + if: needs.config.outputs.runner-count > 0 + runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + shard: ${{ fromJson(needs.config.outputs.ci-matrix) }} + + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/setup + - uses: ./.github/actions/moon-ci + with: + access-token: ${{ secrets.GITHUB_TOKEN }} + + audit: + name: Audit & SCA + needs: [ci] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/setup + - name: Run Moon Audit Tasks (OSV, Cargo, Gitleaks) + run: moon run :audit + + codeql: + name: CodeQL + needs: [ci] + runs-on: ubuntu-latest + permissions: + security-events: write + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/setup + with: + cache-cargo: "false" + cache-pnpm: "false" + - uses: github/codeql-action/init@v3 + with: + languages: javascript + - uses: github/codeql-action/autobuild@v3 + - uses: github/codeql-action/analyze@v3 + + semgrep: + name: Semgrep + needs: [ci] + runs-on: ubuntu-latest + permissions: + security-events: write + container: + image: returntocorp/semgrep + steps: + - uses: actions/checkout@v4 + - name: Run Semgrep scan + run: | + semgrep ci \ + --sarif --output=semgrep.sarif \ + --config="p/default" \ + --config="p/security-audit" \ + --config="p/secrets" + env: + SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@v3 + if: always() + with: + sarif_file: semgrep.sarif + category: semgrep + + release-please: + name: Release Please + needs: [ci, audit, codeql, semgrep] + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - uses: googleapis/release-please-action@v4 + with: + manifest-file: .release-please-manifest.json + config-file: release-please-config.json diff --git a/.github/workflows/pr-close.yml b/.github/workflows/pr-close.yml new file mode 100644 index 0000000..593ed17 --- /dev/null +++ b/.github/workflows/pr-close.yml @@ -0,0 +1,26 @@ +name: PR Review Teardown + +on: + pull_request_target: + types: [closed] + +jobs: + teardown: + name: Review Teardown + runs-on: ubuntu-latest + permissions: + deployments: write + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/setup + + - id: raa + uses: ./.github/actions/moon-raa + with: + command: rm + pr-number: ${{ github.event.pull_request.number }} + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Summary + if: always() + run: echo '${{ steps.raa.outputs.summary }}' >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 0000000..285323c --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,123 @@ +name: Pull Request Pipeline + +on: + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + +concurrency: + group: pr-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + config: + name: CI Strategy + runs-on: ubuntu-latest + outputs: + ci-matrix: ${{ steps.ci-matrix.outputs.matrix }} + runner-count: ${{ steps.ci-matrix.outputs.count }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: ./.github/actions/setup + - id: ci-matrix + uses: ./.github/actions/moon-ci-matrix + + ci: + name: Moon CI + needs: [config] + if: needs.config.outputs.runner-count > 0 + runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + shard: ${{ fromJson(needs.config.outputs.ci-matrix) }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: ./.github/actions/setup + - uses: ./.github/actions/moon-ci + with: + access-token: ${{ secrets.GITHUB_TOKEN }} + + audit: + name: Audit & SCA + needs: [ci] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: ./.github/actions/setup + - name: Run Moon Audit Tasks (OSV, Cargo, Gitleaks) + run: moon run :audit + + codeql: + name: CodeQL + needs: [ci] + runs-on: ubuntu-latest + permissions: + security-events: write + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/setup + with: + cache-cargo: "false" + cache-pnpm: "false" + - uses: github/codeql-action/init@v3 + with: + languages: javascript + - uses: github/codeql-action/autobuild@v3 + - uses: github/codeql-action/analyze@v3 + + semgrep: + name: Semgrep + needs: [ci] + runs-on: ubuntu-latest + permissions: + security-events: write + container: + image: returntocorp/semgrep + steps: + - uses: actions/checkout@v4 + - name: Run Semgrep scan + run: | + semgrep ci \ + --sarif --output=semgrep.sarif \ + --config="p/default" \ + --config="p/security-audit" \ + --config="p/secrets" + env: + SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@v3 + if: always() + with: + sarif_file: semgrep.sarif + category: semgrep + + # Review App & Artifacts (RAA) + review-open: + name: Review Build + if: contains(github.event.pull_request.labels.*.name, 'review-app') + runs-on: ubuntu-latest + needs: [ci] + permissions: + deployments: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: ./.github/actions/setup + + - id: raa + uses: ./.github/actions/moon-raa + with: + command: run + pr-number: ${{ github.event.pull_request.number }} + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Summary + if: always() + run: echo '${{ steps.raa.outputs.summary }}' >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..a252195 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,102 @@ +name: Publish Distribution + +on: + release: + types: [published] + workflow_dispatch: + inputs: + scope: + description: "What to publish/review" + required: true + type: choice + options: + - affected + - all + snapshot: + description: "Run as a snapshot build (no registry publish)" + required: true + type: boolean + default: true + +jobs: + # --------------------------------------------------------- + # 1. Routing Job: Determine Task & Environment + # --------------------------------------------------------- + router: + name: Determine Target + runs-on: ubuntu-latest + outputs: + task: ${{ steps.parse.outputs.task }} + target: ${{ steps.parse.outputs.target }} + environment: ${{ steps.parse.outputs.environment }} + steps: + - id: parse + run: | + # Default values for Workflow Dispatch (Manual Trigger) + TASK="publish" + TARGET="" + ENV="" + + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + if [ "${{ inputs.snapshot }}" == "true" ]; then + TASK="review" + fi + + if [ "${{ inputs.scope }}" == "affected" ]; then + TARGET=":$TASK --affected" + else + TARGET=":$TASK" + fi + fi + + # If triggered by an actual GitHub Release event + if [ "${{ github.event_name }}" == "release" ]; then + TAG="${{ github.event.release.tag_name }}" + COMP=$(echo "$TAG" | sed -E 's/-v[0-9].*//') + + # Check if this is a pre-release (review app) + if [ "${{ github.event.release.prerelease }}" == "true" ]; then + TASK="review" + ENV="" # No manual gate needed for review + else + TASK="publish" + ENV="release" # Require production manual approval + fi + + TARGET="$COMP:$TASK" + fi + + echo "task=$TASK" >> $GITHUB_OUTPUT + echo "target=$TARGET" >> $GITHUB_OUTPUT + echo "environment=$ENV" >> $GITHUB_OUTPUT + + publish: + name: Moon Run ${{ needs.router.outputs.target }} + needs: router + runs-on: ubuntu-latest + environment: ${{ needs.router.outputs.environment }} + permissions: + contents: write + packages: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: ./.github/actions/setup + + - name: Execute Moon Task + run: moon run ${{ needs.router.outputs.target }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }} + + - name: Attach standalone artifacts to release + if: github.event_name == 'release' + run: | + if [ -d dist/ ]; then + gh release upload "${{ github.event.release.tag_name }}" dist/* --clobber + fi + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.moon/tasks/rust.yml b/.moon/tasks/rust.yml index cefd935..6c14a72 100644 --- a/.moon/tasks/rust.yml +++ b/.moon/tasks/rust.yml @@ -72,3 +72,24 @@ tasks: - "@group(tests)" - "/.config/nextest.*" env: *env + + fmt-check: + command: "cargo fmt --check" + inputs: + - "@group(cargo)" + - "@group(sources)" + env: *env + + cargo-audit: + command: "cargo" + args: ["audit"] + inputs: + - "@group(cargo)" + env: *env + + cargo-deny: + command: "cargo" + args: ["deny", "check"] + inputs: + - "@group(cargo)" + env: *env diff --git a/.moon/tasks/security.yml b/.moon/tasks/security.yml new file mode 100644 index 0000000..a59e1f0 --- /dev/null +++ b/.moon/tasks/security.yml @@ -0,0 +1,14 @@ +# $schema: "https://moonrepo.dev/schemas/tasks.json" + +# tasks: +# semgrep: +# command: "semgrep" +# args: ["--config", "auto", "--error", "."] + +# gitleaks: +# command: "gitleaks" +# args: ["detect", "--source", ".", "-v"] + +# tangleguard: +# command: "echo" +# args: ["TangleGuard placeholder \u2014 not yet implemented"] diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 0000000..397c3f5 --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,221 @@ +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + // Built-in plugins only (no UI/react/etc). + "plugins": ["typescript", "import", "unicorn", "promise", "node", "oxc"], + "options": { + // Now that you installed tsgolint, keep this on. + // Equivalent to CLI: --type-aware + "typeAware": true, + // Optional (more expensive): TS compiler diagnostics. + // If you want "tsc-like" feedback during lint, turn on. + "typeCheck": true + }, + "categories": { + // Maximize baseline coverage. + "correctness": "error", + "suspicious": "warn", + // Keep these explicit (don't enable wholesale), to avoid noisy/subjective churn: + "perf": "off", + "pedantic": "off", + "style": "off", + "restriction": "off", + "nursery": "off" + }, + "rules": { + // ───────────────────────────────────────────────────────────── + // STRUCTURE / COMPLEXITY + // These look like formatting but enforce cognitive load limits. + // dprint controls how code *looks*; these control how code *thinks*. + // ───────────────────────────────────────────────────────────── + // SEMANTIC: caps branching depth, enforces guard-clause-first style. + // dprint cannot reason about control flow nesting. + "max-depth": ["error", { "max": 2 }], + // SEMANTIC: caps function size as a complexity proxy. + // dprint line-wrapping changes visual lines, but this counts logical lines + // (skipBlankLines + skipComments), which dprint doesn't track. + "max-lines-per-function": ["warn", { "max": 25, "skipBlankLines": true, "skipComments": true }], + // SEMANTIC: caps cyclomatic complexity (branch count). + // Pure control-flow metric, no formatting tool can replicate this. + "complexity": ["warn", { "max": 5 }], + // SEMANTIC: caps parameter count to enforce small function signatures. + // dprint wraps params visually; this limits how many you can have. + "max-params": ["error", { "max": 3 }], + // SEMANTIC: enforces guard-clause pattern (early return, no else after return). + // This is control-flow shape, not whitespace. dprint cannot decide when + // an else block is logically redundant. + "no-else-return": "error", + // SEMANTIC: bans nested ternaries to prevent unreadable conditional chains. + // dprint formats ternaries but cannot judge nesting depth or readability. + "no-nested-ternary": "error", + // DISABLED: dprint handles ternary formatting; this rule's autofix + // rewrites `x ? true : false` to `!!x` which is a style preference + // that overlaps with typescript/strict-boolean-expressions. + // "no-unneeded-ternary": "error", + // ───────────────────────────────────────────────────────────── + // IMMUTABILITY SUPPORT (closest oxlint can get to functional/immutable-data) + // ───────────────────────────────────────────────────────────── + "no-var": "error", + "prefer-const": "error", + "no-param-reassign": "error", + // DISABLED: pure formatting preference. dprint handles spread formatting + // via its own rules. The *semantic* immutability enforcement comes from + // functional/immutable-data in ESLint. + // "prefer-object-spread": "error", + "no-object-constructor": "error", + "no-array-constructor": "error", + // Perf+immutability footguns + "oxc/no-accumulating-spread": "warn", + // Spread over Object.assign + "unicorn/prefer-spread": "warn", + // ───────────────────────────────────────────────────────────── + // NO NULLS / OPTION-ISH STYLE + // ───────────────────────────────────────────────────────────── + "unicorn/no-null": "warn", + "unicorn/no-useless-undefined": "warn", + "typescript/prefer-nullish-coalescing": "warn", + "typescript/prefer-optional-chain": "warn", + // ───────────────────────────────────────────────────────────── + // DECLARATIVE ITERATION (nudges; ESLint functional still bans loops fully) + // ───────────────────────────────────────────────────────────── + "unicorn/no-for-loop": "error", + "unicorn/no-array-for-each": "warn", + "unicorn/prefer-array-flat-map": "error", + "unicorn/prefer-array-find": "error", + "unicorn/prefer-array-some": "error", + "unicorn/prefer-array-index-of": "error", + "unicorn/no-array-reduce": "allow", + "unicorn/no-array-push-push": "warn", + "unicorn/prefer-set-has": "warn", + // ───────────────────────────────────────────────────────────── + // ASYNC / PROMISE SAFETY (type-aware + runtime-ish) + // ───────────────────────────────────────────────────────────── + "typescript/no-floating-promises": ["error", { "ignoreVoid": true }], + "typescript/no-misused-promises": "error", + "typescript/promise-function-async": "off", + "typescript/return-await": "error", + "unicorn/no-await-in-promise-methods": "error", + "unicorn/no-single-promise-in-promise-methods": "error", + "unicorn/no-unnecessary-await": "error", + "unicorn/no-thenable": "error", + "promise/no-new-statics": "error", + "promise/no-multiple-resolved": "warn", + "promise/valid-params": "error", + // Supports ResultAsync-first stance: loops should use ResultAsync.combine + // or similar, not sequential awaits. + "no-await-in-loop": "warn", + // ───────────────────────────────────────────────────────────── + // TYPE SAFETY / UNION EXHAUSTIVENESS + // ───────────────────────────────────────────────────────────── + "typescript/switch-exhaustiveness-check": "error", + "typescript/strict-boolean-expressions": "warn", + "typescript/no-explicit-any": "warn", + "typescript/no-unsafe-return": "error", + "typescript/no-unsafe-argument": "error", + // "Max coverage" extras (may add noise, but reduce unsafe-any creep) + "typescript/no-unsafe-assignment": "warn", + "typescript/no-unsafe-call": "warn", + "typescript/no-unsafe-member-access": "warn", + "typescript/no-non-null-assertion": "warn", + "typescript/no-unnecessary-type-assertion": "warn", + "typescript/no-unnecessary-type-arguments": "warn", + // Discriminated unions over interfaces: enforce `type` keyword + "typescript/consistent-type-definitions": ["error", "type"], + // Keep TS escape hatches honest + "typescript/ban-ts-comment": [ + "warn", + { + "ts-ignore": "allow-with-description", + "ts-expect-error": "allow-with-description", + "ts-nocheck": true, + "minimumDescriptionLength": 5 + } + ], + // ───────────────────────────────────────────────────────────── + // MODULE HYGIENE / IMPORTS + // ───────────────────────────────────────────────────────────── + "import/no-default-export": "error", + "import/no-cycle": "error", + "import/no-self-import": "error", + // DISABLED: dprint handles import deduplication and sorting via + // module.sortImportDeclarations and importDeclaration.sortNamedImports. + // "import/no-duplicates": "warn", + "typescript/consistent-type-imports": "warn", + // ───────────────────────────────────────────────────────────── + // NODE/BUN SERVER HYGIENE + // ───────────────────────────────────────────────────────────── + "node/no-exports-assign": "error", + "node/no-new-require": "error", + "node/no-path-concat": "error", + "node/no-process-env": "warn", + "unicorn/prefer-node-protocol": "error", + // ───────────────────────────────────────────────────────────── + // ERROR QUALITY (even if you avoid throw, shells still throw sometimes) + // ───────────────────────────────────────────────────────────── + "unicorn/error-message": "error", + "unicorn/throw-new-error": "error", + "unicorn/prefer-type-error": "warn", + "no-throw-literal": "error", + "prefer-promise-reject-errors": "error", + // ───────────────────────────────────────────────────────────── + // FP-ADJACENT "NO CLASSES AS NAMESPACES" HELPERS + // (not a full ban; ESLint functional still does the heavy lifting) + // ───────────────────────────────────────────────────────────── + "unicorn/no-static-only-class": "error", + "typescript/no-extraneous-class": "warn", + "class-methods-use-this": "warn", + // ───────────────────────────────────────────────────────────── + // GENERAL HYGIENE + // ───────────────────────────────────────────────────────────── + "no-console": ["warn", { "allow": ["error", "warn"] }], + "no-debugger": "error", + "no-eval": "error", + "eqeqeq": "error", + "no-implicit-coercion": "error", + "no-shadow": "warn", + "no-magic-numbers": ["warn", { "ignore": [0, 1, -1], "enforceConst": true }], + "no-void": ["error", { "allowAsStatement": true }], + "unicorn/no-empty-file": "error", + // Subtle "dead code" / refactor safety + "no-useless-assignment": "warn", + // Small performance-ish correctness + "oxc/approx-constant": "warn", + "no-useless-call": "warn", + // (Opinionated restrictions that typically match FP/clarity) + "no-labels": "error", + "no-with": "error", + "no-sequences": "error", + "no-extend-native": "error", + "no-proto": "error", + "no-iterator": "error", + "no-new-wrappers": "error", + "no-bitwise": "warn", + "arrow-body-style": ["warn", "as-needed"], + "unicorn/prefer-ternary": ["warn", "only-single-line"], + // Positive predicates: prefer `if (ready)` over `if (!notReady)` + "unicorn/no-negated-condition": "warn" + }, + "overrides": [{ + // TESTS: loosen ergonomics + "files": ["*.spec.ts", "*.test.ts", "src/test/**/*.ts"], + "rules": { + "max-params": "off", + "max-depth": "off", + "max-lines-per-function": "off", + "complexity": "off", + "no-magic-numbers": "off", + "no-param-reassign": "off", + "typescript/no-explicit-any": "off", + "typescript/no-unsafe-argument": "off", + "typescript/no-unsafe-return": "off", + "typescript/no-unsafe-assignment": "off", + "typescript/no-unsafe-call": "off", + "typescript/no-unsafe-member-access": "off", + "typescript/no-non-null-assertion": "off", + "unicorn/no-null": "off", + "unicorn/no-array-reduce": "off", + "unicorn/consistent-function-scoping": "off", + "node/no-process-env": "off" + } + }], + "ignorePatterns": ["node_modules", "dist"] +} diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..11ea174 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,12 @@ +{ + "parser": "0.1.0", + "wasm-javascript": "0.1.0", + "wasm-wasi": "0.1.0", + "spec": "0.1.0", + "riff-cli": "0.1.0", + "slash-rust": "0.1.0", + "slash-javascript": "0.1.0", + "slash-web": "0.1.0", + "slash-python": "0.1.0", + "slash-go": "0.1.0" +} diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..dc9e5fa --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,36 @@ +# ── Core: match dprint.json + .editorconfig ───────────────────── +# Match dprint lineWidth +max_width = 110 +# Match editorconfig indent_style = space +hard_tabs = false +# Rust community standard (differs from your TS indent of 2, intentionally) +tab_spaces = 4 +# Match editorconfig end_of_line = lf +newline_style = "Unix" +# Like TS shorthand { id } instead of { id: id } +use_field_init_shorthand = true + +# ── Expression density: match dprint preferSingleLine ─────────── +# Rustfmt defaults to breaking things across lines aggressively. +# These keep short expressions on one line (same intent as dprint's preferSingleLine). +# Allow short fn bodies on one line +fn_single_line = true +# Maximize single-line formatting for structs, calls, arrays, chains +use_small_heuristics = "Max" + +# ── Imports: match dprint's sort behavior ──────────────────────── +# Alphabetical sort (matches dprint module.sortImportDeclarations) +reorder_imports = true +# Keep mod declarations sorted too +reorder_modules = true + +# ── Unstable (require nightly rustfmt or cargo +nightly fmt) ───── +# These are high-value options worth running nightly fmt for. +# If you must stay on stable, comment these out; they'll emit warnings but not break. +unstable_features = true +# Merge imports per crate (reduces visual noise) +imports_granularity = "Crate" +# Group: std → external crates → crate (clean architecture readability) +group_imports = "StdExternalCrate" +# Keep doc examples formatted +format_code_in_doc_comments = true diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..4c2075a --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,187 @@ +import boundaries from 'eslint-plugin-boundaries' +import functional from 'eslint-plugin-functional' +import oxlint from 'eslint-plugin-oxlint' +import preferArrowFunctions from 'eslint-plugin-prefer-arrow-functions' +import { defineConfig } from 'eslint/config' +import tseslint from 'typescript-eslint' + +// ── Boundary mode ────────────────────────────────────────────── +// "feature" → src/orders/domain.ts, src/orders/use-cases.ts, ... +// "layer" → src/domain/orders.ts, src/application/orders.ts, ... +// "none" → no boundary enforcement +const BOUNDARY_MODE = 'feature' + +// ── Boundary element definitions per mode ────────────────────── +const boundaryElements = { + feature: [ + { type: 'domain', pattern: ['src/*/domain.ts', 'src/*/domain/**'] }, + { type: 'application', pattern: ['src/*/use-cases.ts', 'src/*/logic.ts', 'src/*/ports.ts'] }, + { type: 'infrastructure', pattern: ['src/*/repo.ts', 'src/*/io.ts', 'src/*/adapter.ts', 'src/cli/**'] }, + { type: 'shared', pattern: ['src/shared/**'] }, + { type: 'composition', pattern: ['src/main.ts'] }, + { type: 'test', pattern: ['src/**/*.spec.ts', 'src/test/**'] }, + ], + layer: [ + { type: 'domain', pattern: ['src/domain/**'] }, + { type: 'application', pattern: ['src/application/**'] }, + { type: 'infrastructure', pattern: ['src/infrastructure/**'] }, + { type: 'shared', pattern: ['src/shared/**'] }, + { type: 'composition', pattern: ['src/main.ts'] }, + { type: 'test', pattern: ['src/**/*.spec.ts', 'src/test/**'] }, + ], +} + +// Dependency inversion: inner layers cannot import outer layers +const boundaryRules = [ + { from: 'domain', allow: ['domain', 'shared'] }, + { from: 'application', allow: ['domain', 'application', 'shared'] }, + { from: 'infrastructure', allow: ['domain', 'application', 'infrastructure', 'shared'] }, + { from: 'composition', allow: ['domain', 'application', 'infrastructure', 'shared', 'composition'] }, + { from: 'test', allow: ['domain', 'application', 'infrastructure', 'shared', 'test'] }, +] + +// Domain file globs (used for purity + FP strictness overrides) +const domainFiles = BOUNDARY_MODE === 'feature' ? + ['src/*/domain.ts', 'src/*/domain/**/*.ts'] : + ['src/domain/**/*.ts'] + +// Infra file globs (relaxed FP rules) +const infraFiles = BOUNDARY_MODE === 'feature' ? + ['src/*/repo.ts', 'src/*/io.ts', 'src/*/adapter.ts', 'src/cli/**/*.ts'] : + ['src/infrastructure/**/*.ts'] + +// ── Functional rules (global defaults) ───────────────────────── +// These are the core FP rules that oxlint cannot replicate. +// ESLint owns all functional/* enforcement. +const functionalRules = { + 'functional/no-loop-statements': 'error', + 'functional/no-try-statements': 'error', + 'functional/no-throw-statements': 'error', + 'functional/no-let': ['error', { allowInForLoopInit: false }], + 'functional/no-classes': 'error', + 'functional/no-this-expressions': 'error', + 'functional/immutable-data': ['warn', { ignoreImmediateMutation: true, ignoreClasses: true }], + 'functional/prefer-readonly-type': 'warn', + 'functional/no-expression-statements': ['error', { + ignoreVoid: true, + ignoreCodePattern: ['^expect', '^assert'], + }], + 'functional/no-return-void': 'error', +} + +// ── AST selector bans (oxlint cannot do ESQuery selectors) ───── +const restrictedSyntax = ['error', { + selector: ":function > Identifier.params[typeAnnotation.typeAnnotation.type='TSBooleanKeyword']", + message: 'Boolean params are banned. Split into separate functions.', +}, { + selector: "CallExpression[callee.property.name='_unsafeUnwrap']", + message: 'Use .map(), .andThen(), or .match() instead.', +}, { + selector: "CallExpression[callee.property.name='_unsafeUnwrapErr']", + message: 'Use .mapErr(), .andThen(), or .match() instead.', +}] + +// ── Domain purity: ban IO imports in domain files ────────────── +const domainImportBans = { + patterns: [{ + group: ['fs', 'fs/*', 'path', 'http', 'https', 'net', 'child_process', 'crypto'], + message: 'Domain must be pure. No Node.js IO.', + }, { + group: ['express', 'fastify', 'koa', 'hono', 'elysia'], + message: 'Domain must be pure. No HTTP frameworks.', + }, { + group: ['pg', 'mysql*', 'redis', 'ioredis', 'mongoose', '@prisma/*', 'kysely'], + message: 'Domain must be pure. No database drivers.', + }, { + group: ['@aws-sdk/*', '@azure/*', '@google-cloud/*'], + message: 'Domain must be pure. No cloud SDKs.', + }], +} + +// ── Build config array ───────────────────────────────────────── +const config = [ + { ignores: ['node_modules/**', 'dist/**', 'eslint.config.mjs'] }, + + // Global: all source files + { + files: ['src/**/*.ts'], + languageOptions: { + parser: tseslint.parser, + parserOptions: { projectService: true, tsconfigRootDir: import.meta.dirname }, + }, + plugins: { + functional, + 'prefer-arrow-functions': preferArrowFunctions, + ...(BOUNDARY_MODE !== 'none' && { boundaries }), + }, + ...(BOUNDARY_MODE !== 'none' && { settings: { 'boundaries/elements': boundaryElements[BOUNDARY_MODE] } }), + rules: { + ...functionalRules, + 'no-restricted-syntax': restrictedSyntax, + + // Arrow function enforcement: ESLint owns the *semantic* rule + // (must use arrows). dprint owns arrow *formatting* (parens, wrapping). + 'prefer-arrow-functions/prefer-arrow-functions': ['error', { + allowNamedFunctions: false, + classPropertiesAllowed: false, + disallowPrototype: true, + returnStyle: 'unchanged', + singleReturnOnly: false, + }], + + // Boundaries (only when enabled) + ...(BOUNDARY_MODE !== 'none' && + { 'boundaries/element-types': ['error', { default: 'disallow', rules: boundaryRules }] }), + }, + }, + + // Domain purity: ban IO imports + { + files: domainFiles, + rules: { + 'no-restricted-imports': ['error', domainImportBans], + 'functional/prefer-readonly-type': 'error', + }, + }, + + // Tests: fully relax FP rules + { + files: ['src/**/*.spec.ts', 'src/test/**/*.ts'], + rules: { + 'functional/no-let': 'off', + 'functional/no-loop-statements': 'off', + 'functional/no-try-statements': 'off', + 'functional/no-throw-statements': 'off', + 'functional/no-expression-statements': 'off', + 'functional/no-return-void': 'off', + 'functional/immutable-data': 'off', + 'functional/no-classes': 'off', + 'functional/no-this-expressions': 'off', + 'no-restricted-syntax': 'off', + }, + }, + + // Infrastructure: imperative shell allowances + { + files: infraFiles, + rules: { + 'functional/no-let': 'warn', + 'functional/no-loop-statements': 'warn', + 'functional/no-try-statements': 'off', + 'functional/no-throw-statements': 'off', + 'functional/no-expression-statements': 'off', + 'functional/no-return-void': 'off', + 'functional/immutable-data': 'off', + 'functional/no-classes': ['error', { + ignoreIdentifierPattern: '^.*(Controller|Adapter|Module|Client|Provider|Gateway)$', + }], + 'functional/no-this-expressions': 'off', + }, + }, + + // Deduplicate: turn off anything oxlint already handles + ...oxlint.buildFromOxlintConfigFile('./.oxlintrc.json'), +] + +// eslint-disable no-default-export +export default defineConfig(...config) diff --git a/moon.yml b/moon.yml new file mode 100644 index 0000000..a0d8a60 --- /dev/null +++ b/moon.yml @@ -0,0 +1,25 @@ +$schema: "https://moonrepo.dev/schemas/project.json" + +tags: + - "tooling" + +tasks: + fmt: + script: "rustup toolchain install nightly --component rustfmt -q && dprint fmt" + inputs: + - "**/*.rs" + - "**/*.toml" + - "**/*.yml" + - "**/*.yaml" + - "dprint.json" + options: + runInCI: false + + fmt-check: + script: "rustup toolchain install nightly --component rustfmt -q && dprint check" + inputs: + - "**/*.rs" + - "**/*.toml" + - "**/*.yml" + - "**/*.yaml" + - "dprint.json" diff --git a/parser/moon.yml b/parser/moon.yml index 202ffcd..93a9f0c 100644 --- a/parser/moon.yml +++ b/parser/moon.yml @@ -3,8 +3,6 @@ id: "parser" language: "rust" tags: ["core"] - workspace: inheritedTasks: include: [] - diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..5f04c6e --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,1839 @@ +lockfileVersion: "9.0" + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + slash-parser-js: + devDependencies: + "@types/bun": + specifier: latest + version: 1.3.10 + eslint: + specifier: ^9.0.0 + version: 9.39.4 + eslint-plugin-boundaries: + specifier: ^5.0.0 + version: 5.4.0(eslint@9.39.4) + eslint-plugin-functional: + specifier: ^9.0.0 + version: 9.0.4(eslint@9.39.4)(typescript@5.9.3) + eslint-plugin-oxlint: + specifier: ^1.51.0 + version: 1.55.0 + eslint-plugin-prefer-arrow-functions: + specifier: ^3.6.0 + version: 3.9.1(eslint@9.39.4)(typescript@5.9.3) + fast-check: + specifier: ^3.0.0 + version: 3.23.2 + oxlint: + specifier: ^1.0.0 + version: 1.55.0(oxlint-tsgolint@0.16.0) + oxlint-tsgolint: + specifier: ^0.16.0 + version: 0.16.0 + typescript: + specifier: ^5.5.0 + version: 5.9.3 + +packages: + "@boundaries/elements@1.2.0": + resolution: { + integrity: sha512-W65Gum02liMd3hmNrLmDBX1u5BmRMcunouFjLXyhxHnNY4YlK1kTxsgfflZ5XBGSnPnO0MkiUzAcoGzYrlx0RQ==, + } + engines: { node: ">=18.18" } + + "@eslint-community/eslint-utils@4.9.1": + resolution: { + integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + "@eslint-community/regexpp@4.12.2": + resolution: { + integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==, + } + engines: { node: ^12.0.0 || ^14.0.0 || >=16.0.0 } + + "@eslint/config-array@0.21.2": + resolution: { + integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + "@eslint/config-helpers@0.4.2": + resolution: { + integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + "@eslint/core@0.17.0": + resolution: { + integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + "@eslint/eslintrc@3.3.5": + resolution: { + integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + "@eslint/js@9.39.4": + resolution: { + integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + "@eslint/object-schema@2.1.7": + resolution: { + integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + "@eslint/plugin-kit@0.4.1": + resolution: { + integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + "@humanfs/core@0.19.1": + resolution: { + integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==, + } + engines: { node: ">=18.18.0" } + + "@humanfs/node@0.16.7": + resolution: { + integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==, + } + engines: { node: ">=18.18.0" } + + "@humanwhocodes/module-importer@1.0.1": + resolution: { + integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==, + } + engines: { node: ">=12.22" } + + "@humanwhocodes/retry@0.4.3": + resolution: { + integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==, + } + engines: { node: ">=18.18" } + + "@oxlint-tsgolint/darwin-arm64@0.16.0": + resolution: { + integrity: sha512-WQt5lGwRPJBw7q2KNR0mSPDAaMmZmVvDlEEti96xLO7ONhyomQc6fBZxxwZ4qTFedjJnrHX94sFelZ4OKzS7UQ==, + } + cpu: [arm64] + os: [darwin] + + "@oxlint-tsgolint/darwin-x64@0.16.0": + resolution: { + integrity: sha512-VJo29XOzdkalvCTiE2v6FU3qZlgHaM8x8hUEVJGPU2i5W+FlocPpmn00+Ld2n7Q0pqIjyD5EyvZ5UmoIEJMfqg==, + } + cpu: [x64] + os: [darwin] + + "@oxlint-tsgolint/linux-arm64@0.16.0": + resolution: { + integrity: sha512-MPfqRt1+XRHv9oHomcBMQ3KpTE+CSkZz14wUxDQoqTNdUlV0HWdzwIE9q65I3D9YyxEnqpM7j4qtDQ3apqVvbQ==, + } + cpu: [arm64] + os: [linux] + + "@oxlint-tsgolint/linux-x64@0.16.0": + resolution: { + integrity: sha512-XQSwVUsnwLokMhe1TD6IjgvW5WMTPzOGGkdFDtXWQmlN2YeTw94s/NN0KgDrn2agM1WIgAenEkvnm0u7NgwEyw==, + } + cpu: [x64] + os: [linux] + + "@oxlint-tsgolint/win32-arm64@0.16.0": + resolution: { + integrity: sha512-EWdlspQiiFGsP2AiCYdhg5dTYyAlj6y1nRyNI2dQWq4Q/LITFHiSRVPe+7m7K7lcsZCEz2icN/bCeSkZaORqIg==, + } + cpu: [arm64] + os: [win32] + + "@oxlint-tsgolint/win32-x64@0.16.0": + resolution: { + integrity: sha512-1ufk8cgktXJuJZHKF63zCHAkaLMwZrEXnZ89H2y6NO85PtOXqu4zbdNl0VBpPP3fCUuUBu9RvNqMFiv0VsbXWA==, + } + cpu: [x64] + os: [win32] + + "@oxlint/binding-android-arm-eabi@1.55.0": + resolution: { + integrity: sha512-NhvgAhncTSOhRahQSCnkK/4YIGPjTmhPurQQ2dwt2IvwCMTvZRW5vF2K10UBOxFve4GZDMw6LtXZdC2qeuYIVQ==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [arm] + os: [android] + + "@oxlint/binding-android-arm64@1.55.0": + resolution: { + integrity: sha512-P9iWRh+Ugqhg+D7rkc7boHX8o3H2h7YPcZHQIgvVBgnua5tk4LR2L+IBlreZs58/95cd2x3/004p5VsQM9z4SA==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [arm64] + os: [android] + + "@oxlint/binding-darwin-arm64@1.55.0": + resolution: { + integrity: sha512-esakkJIt7WFAhT30P/Qzn96ehFpzdZ1mNuzpOb8SCW7lI4oB8VsyQnkSHREM671jfpuBb/o2ppzBCx5l0jpgMA==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [arm64] + os: [darwin] + + "@oxlint/binding-darwin-x64@1.55.0": + resolution: { + integrity: sha512-xDMFRCCAEK9fOH6As2z8ELsC+VDGSFRHwIKVSilw+xhgLwTDFu37rtmRbmUlx8rRGS6cWKQPTc47AVxAZEVVPQ==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [x64] + os: [darwin] + + "@oxlint/binding-freebsd-x64@1.55.0": + resolution: { + integrity: sha512-mYZqnwUD7ALCRxGenyLd1uuG+rHCL+OTT6S8FcAbVm/ZT2AZMGjvibp3F6k1SKOb2aeqFATmwRykrE41Q0GWVw==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [x64] + os: [freebsd] + + "@oxlint/binding-linux-arm-gnueabihf@1.55.0": + resolution: { + integrity: sha512-LcX6RYcF9vL9ESGwJW3yyIZ/d/ouzdOKXxCdey1q0XJOW1asrHsIg5MmyKdEBR4plQx+shvYeQne7AzW5f3T1w==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [arm] + os: [linux] + + "@oxlint/binding-linux-arm-musleabihf@1.55.0": + resolution: { + integrity: sha512-C+8GS1rPtK+dI7mJFkqoRBkDuqbrNihnyYQsJPS9ez+8zF9JzfvU19lawqt4l/Y23o5uQswE/DORa8aiXUih3w==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [arm] + os: [linux] + + "@oxlint/binding-linux-arm64-gnu@1.55.0": + resolution: { + integrity: sha512-ErLE4XbmcCopA4/CIDiH6J1IAaDOMnf/KSx/aFObs4/OjAAM3sFKWGZ57pNOMxhhyBdcmcXwYymph9GwcpcqgQ==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [arm64] + os: [linux] + libc: [glibc] + + "@oxlint/binding-linux-arm64-musl@1.55.0": + resolution: { + integrity: sha512-/kp65avi6zZfqEng56TTuhiy3P/3pgklKIdf38yvYeJ9/PgEeRA2A2AqKAKbZBNAqUzrzHhz9jF6j/PZvhJzTQ==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [arm64] + os: [linux] + libc: [musl] + + "@oxlint/binding-linux-ppc64-gnu@1.55.0": + resolution: { + integrity: sha512-A6pTdXwcEEwL/nmz0eUJ6WxmxcoIS+97GbH96gikAyre3s5deC7sts38ZVVowjS2QQFuSWkpA4ZmQC0jZSNvJQ==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [ppc64] + os: [linux] + libc: [glibc] + + "@oxlint/binding-linux-riscv64-gnu@1.55.0": + resolution: { + integrity: sha512-clj0lnIN+V52G9tdtZl0LbdTSurnZ1NZj92Je5X4lC7gP5jiCSW+Y/oiDiSauBAD4wrHt2S7nN3pA0zfKYK/6Q==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [riscv64] + os: [linux] + libc: [glibc] + + "@oxlint/binding-linux-riscv64-musl@1.55.0": + resolution: { + integrity: sha512-NNu08pllN5x/O94/sgR3DA8lbrGBnTHsINZZR0hcav1sj79ksTiKKm1mRzvZvacwQ0hUnGinFo+JO75ok2PxYg==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [riscv64] + os: [linux] + libc: [musl] + + "@oxlint/binding-linux-s390x-gnu@1.55.0": + resolution: { + integrity: sha512-BvfQz3PRlWZRoEZ17dZCqgQsMRdpzGZomJkVATwCIGhHVVeHJMQdmdXPSjcT1DCNUrOjXnVyj1RGDj5+/Je2+Q==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [s390x] + os: [linux] + libc: [glibc] + + "@oxlint/binding-linux-x64-gnu@1.55.0": + resolution: { + integrity: sha512-ngSOoFCSBMKVQd24H8zkbcBNc7EHhjnF1sv3mC9NNXQ/4rRjI/4Dj9+9XoDZeFEkF1SX1COSBXF1b2Pr9rqdEw==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [x64] + os: [linux] + libc: [glibc] + + "@oxlint/binding-linux-x64-musl@1.55.0": + resolution: { + integrity: sha512-BDpP7W8GlaG7BR6QjGZAleYzxoyKc/D24spZIF2mB3XsfALQJJT/OBmP8YpeTb1rveFSBHzl8T7l0aqwkWNdGA==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [x64] + os: [linux] + libc: [musl] + + "@oxlint/binding-openharmony-arm64@1.55.0": + resolution: { + integrity: sha512-PS6GFvmde/pc3fCA2Srt51glr8Lcxhpf6WIBFfLphndjRrD34NEcses4TSxQrEcxYo6qVywGfylM0ZhSCF2gGA==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [arm64] + os: [openharmony] + + "@oxlint/binding-win32-arm64-msvc@1.55.0": + resolution: { + integrity: sha512-P6JcLJGs/q1UOvDLzN8otd9JsH4tsuuPDv+p7aHqHM3PrKmYdmUvkNj4K327PTd35AYcznOCN+l4ZOaq76QzSw==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [arm64] + os: [win32] + + "@oxlint/binding-win32-ia32-msvc@1.55.0": + resolution: { + integrity: sha512-gzkk4zE2zsE+WmRxFOiAZHpCpUNDFytEakqNXoNHW+PnYEOTPKDdW6nrzgSeTbGKVPXNAKQnRnMgrh7+n3Xueg==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [ia32] + os: [win32] + + "@oxlint/binding-win32-x64-msvc@1.55.0": + resolution: { + integrity: sha512-ZFALNow2/og75gvYzNP7qe+rREQ5xunktwA+lgykoozHZ6hw9bqg4fn5j2UvG4gIn1FXqrZHkOAXuPf5+GOYTQ==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [x64] + os: [win32] + + "@types/bun@1.3.10": + resolution: { + integrity: sha512-0+rlrUrOrTSskibryHbvQkDOWRJwJZqZlxrUs1u4oOoTln8+WIXBPmAuCF35SWB2z4Zl3E84Nl/D0P7803nigQ==, + } + + "@types/estree@1.0.8": + resolution: { + integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==, + } + + "@types/json-schema@7.0.15": + resolution: { + integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==, + } + + "@types/node@25.5.0": + resolution: { + integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==, + } + + "@typescript-eslint/project-service@8.57.0": + resolution: { + integrity: sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + typescript: ">=4.8.4 <6.0.0" + + "@typescript-eslint/scope-manager@8.57.0": + resolution: { + integrity: sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + "@typescript-eslint/tsconfig-utils@8.57.0": + resolution: { + integrity: sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + typescript: ">=4.8.4 <6.0.0" + + "@typescript-eslint/type-utils@8.57.0": + resolution: { + integrity: sha512-yjgh7gmDcJ1+TcEg8x3uWQmn8ifvSupnPfjP21twPKrDP/pTHlEQgmKcitzF/rzPSmv7QjJ90vRpN4U+zoUjwQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.0.0" + + "@typescript-eslint/types@8.57.0": + resolution: { + integrity: sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + "@typescript-eslint/typescript-estree@8.57.0": + resolution: { + integrity: sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + typescript: ">=4.8.4 <6.0.0" + + "@typescript-eslint/utils@8.57.0": + resolution: { + integrity: sha512-5iIHvpD3CZe06riAsbNxxreP+MuYgVUsV0n4bwLH//VJmgtt54sQeY2GszntJ4BjYCpMzrfVh2SBnUQTtys2lQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.0.0" + + "@typescript-eslint/visitor-keys@8.57.0": + resolution: { + integrity: sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + acorn-jsx@5.3.2: + resolution: { + integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==, + } + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.16.0: + resolution: { + integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==, + } + engines: { node: ">=0.4.0" } + hasBin: true + + ajv@6.14.0: + resolution: { + integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==, + } + + ansi-styles@4.3.0: + resolution: { + integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==, + } + engines: { node: ">=8" } + + argparse@2.0.1: + resolution: { + integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, + } + + balanced-match@1.0.2: + resolution: { + integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, + } + + balanced-match@4.0.4: + resolution: { + integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==, + } + engines: { node: 18 || 20 || >=22 } + + brace-expansion@1.1.12: + resolution: { + integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==, + } + + brace-expansion@5.0.4: + resolution: { + integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==, + } + engines: { node: 18 || 20 || >=22 } + + braces@3.0.3: + resolution: { + integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==, + } + engines: { node: ">=8" } + + bun-types@1.3.10: + resolution: { + integrity: sha512-tcpfCCl6XWo6nCVnpcVrxQ+9AYN1iqMIzgrSKYMB/fjLtV2eyAVEg7AxQJuCq/26R6HpKWykQXuSOq/21RYcbg==, + } + + callsites@3.1.0: + resolution: { + integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==, + } + engines: { node: ">=6" } + + chalk@4.1.2: + resolution: { + integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==, + } + engines: { node: ">=10" } + + color-convert@2.0.1: + resolution: { + integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==, + } + engines: { node: ">=7.0.0" } + + color-name@1.1.4: + resolution: { + integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, + } + + concat-map@0.0.1: + resolution: { + integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==, + } + + cross-spawn@7.0.6: + resolution: { + integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==, + } + engines: { node: ">= 8" } + + debug@3.2.7: + resolution: { + integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==, + } + peerDependencies: + supports-color: "*" + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.3: + resolution: { + integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==, + } + engines: { node: ">=6.0" } + peerDependencies: + supports-color: "*" + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: { + integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==, + } + + deepmerge-ts@7.1.5: + resolution: { + integrity: sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==, + } + engines: { node: ">=16.0.0" } + + escape-string-regexp@4.0.0: + resolution: { + integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==, + } + engines: { node: ">=10" } + + escape-string-regexp@5.0.0: + resolution: { + integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==, + } + engines: { node: ">=12" } + + eslint-import-resolver-node@0.3.9: + resolution: { + integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==, + } + + eslint-module-utils@2.12.1: + resolution: { + integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==, + } + engines: { node: ">=4" } + peerDependencies: + "@typescript-eslint/parser": "*" + eslint: "*" + eslint-import-resolver-node: "*" + eslint-import-resolver-typescript: "*" + eslint-import-resolver-webpack: "*" + peerDependenciesMeta: + "@typescript-eslint/parser": + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-boundaries@5.4.0: + resolution: { + integrity: sha512-6SQmEhXCqGrrxm9YiM24SC95CqrVi2MUOm5SDrfquceh/os8MIAvZYsDU69zvtCSb1S6UbNEmdioi1gCDc8+VQ==, + } + engines: { node: ">=18.18" } + peerDependencies: + eslint: ">=6.0.0" + + eslint-plugin-functional@9.0.4: + resolution: { + integrity: sha512-zm4qaoqb2r50V4WXxt0Mj92buXGMECYvMxGQ6sSb+XeJ+Eec6zCHuMY2+AWK1mqiApvUz2tCtp1P3zcEPU0huw==, + } + engines: { node: ">=v18.18.0" } + peerDependencies: + eslint: ^9.0.0 || ^10.0.0 + typescript: ">=4.7.4" + peerDependenciesMeta: + typescript: + optional: true + + eslint-plugin-oxlint@1.55.0: + resolution: { + integrity: sha512-5ng7DOuikSE64e7hX2HBqEWdmql+Q4FWppBoBkxKKflLt1j9LXhab5BN3bYJKyrAihuK1/VH2JvfNefeOZAqpA==, + } + + eslint-plugin-prefer-arrow-functions@3.9.1: + resolution: { + integrity: sha512-Mr9Ia8i5ohfCMcZBRedXXWdDJIo30gdKdPfRQ5DtO62yzogB5ErVGwQWPz+ycRlQPKpCAlBHpJdp1TCeCtt+YA==, + } + engines: { node: ">=18.0.0" } + peerDependencies: + eslint: ">=9.17.0" + + eslint-scope@8.4.0: + resolution: { + integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + eslint-visitor-keys@3.4.3: + resolution: { + integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + + eslint-visitor-keys@4.2.1: + resolution: { + integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + eslint-visitor-keys@5.0.1: + resolution: { + integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + + eslint@9.39.4: + resolution: { + integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + hasBin: true + peerDependencies: + jiti: "*" + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: { + integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + esquery@1.7.0: + resolution: { + integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==, + } + engines: { node: ">=0.10" } + + esrecurse@4.3.0: + resolution: { + integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==, + } + engines: { node: ">=4.0" } + + estraverse@5.3.0: + resolution: { + integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==, + } + engines: { node: ">=4.0" } + + esutils@2.0.3: + resolution: { + integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==, + } + engines: { node: ">=0.10.0" } + + fast-check@3.23.2: + resolution: { + integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==, + } + engines: { node: ">=8.0.0" } + + fast-deep-equal@3.1.3: + resolution: { + integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, + } + + fast-json-stable-stringify@2.1.0: + resolution: { + integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==, + } + + fast-levenshtein@2.0.6: + resolution: { + integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==, + } + + fdir@6.5.0: + resolution: { + integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==, + } + engines: { node: ">=12.0.0" } + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: { + integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==, + } + engines: { node: ">=16.0.0" } + + fill-range@7.1.1: + resolution: { + integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==, + } + engines: { node: ">=8" } + + find-up@5.0.0: + resolution: { + integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==, + } + engines: { node: ">=10" } + + flat-cache@4.0.1: + resolution: { + integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==, + } + engines: { node: ">=16" } + + flatted@3.4.1: + resolution: { + integrity: sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==, + } + + function-bind@1.1.2: + resolution: { + integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==, + } + + glob-parent@6.0.2: + resolution: { + integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==, + } + engines: { node: ">=10.13.0" } + + globals@14.0.0: + resolution: { + integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==, + } + engines: { node: ">=18" } + + handlebars@4.7.8: + resolution: { + integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==, + } + engines: { node: ">=0.4.7" } + hasBin: true + + has-flag@4.0.0: + resolution: { + integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==, + } + engines: { node: ">=8" } + + hasown@2.0.2: + resolution: { + integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==, + } + engines: { node: ">= 0.4" } + + ignore@5.3.2: + resolution: { + integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==, + } + engines: { node: ">= 4" } + + import-fresh@3.3.1: + resolution: { + integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==, + } + engines: { node: ">=6" } + + imurmurhash@0.1.4: + resolution: { + integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==, + } + engines: { node: ">=0.8.19" } + + is-core-module@2.16.1: + resolution: { + integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==, + } + engines: { node: ">= 0.4" } + + is-extglob@2.1.1: + resolution: { + integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, + } + engines: { node: ">=0.10.0" } + + is-glob@4.0.3: + resolution: { + integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==, + } + engines: { node: ">=0.10.0" } + + is-immutable-type@5.0.1: + resolution: { + integrity: sha512-LkHEOGVZZXxGl8vDs+10k3DvP++SEoYEAJLRk6buTFi6kD7QekThV7xHS0j6gpnUCQ0zpud/gMDGiV4dQneLTg==, + } + peerDependencies: + eslint: "*" + typescript: ">=4.7.4" + + is-number@7.0.0: + resolution: { + integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==, + } + engines: { node: ">=0.12.0" } + + isexe@2.0.0: + resolution: { + integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, + } + + js-yaml@4.1.1: + resolution: { + integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==, + } + hasBin: true + + json-buffer@3.0.1: + resolution: { + integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==, + } + + json-schema-traverse@0.4.1: + resolution: { + integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==, + } + + json-stable-stringify-without-jsonify@1.0.1: + resolution: { + integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==, + } + + jsonc-parser@3.3.1: + resolution: { + integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==, + } + + keyv@4.5.4: + resolution: { + integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==, + } + + levn@0.4.1: + resolution: { + integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==, + } + engines: { node: ">= 0.8.0" } + + locate-path@6.0.0: + resolution: { + integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==, + } + engines: { node: ">=10" } + + lodash.merge@4.6.2: + resolution: { + integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==, + } + + micromatch@4.0.8: + resolution: { + integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==, + } + engines: { node: ">=8.6" } + + minimatch@10.2.4: + resolution: { + integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==, + } + engines: { node: 18 || 20 || >=22 } + + minimatch@3.1.5: + resolution: { + integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==, + } + + minimist@1.2.8: + resolution: { + integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==, + } + + ms@2.1.3: + resolution: { + integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, + } + + natural-compare@1.4.0: + resolution: { + integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==, + } + + neo-async@2.6.2: + resolution: { + integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==, + } + + optionator@0.9.4: + resolution: { + integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==, + } + engines: { node: ">= 0.8.0" } + + oxlint-tsgolint@0.16.0: + resolution: { + integrity: sha512-4RuJK2jP08XwqtUu+5yhCbxEauCm6tv2MFHKEMsjbosK2+vy5us82oI3VLuHwbNyZG7ekZA26U2LLHnGR4frIA==, + } + hasBin: true + + oxlint@1.55.0: + resolution: { + integrity: sha512-T+FjepiyWpaZMhekqRpH8Z3I4vNM610p6w+Vjfqgj5TZUxHXl7N8N5IPvmOU8U4XdTRxqtNNTh9Y4hLtr7yvFg==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + hasBin: true + peerDependencies: + oxlint-tsgolint: ">=0.15.0" + peerDependenciesMeta: + oxlint-tsgolint: + optional: true + + p-limit@3.1.0: + resolution: { + integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==, + } + engines: { node: ">=10" } + + p-locate@5.0.0: + resolution: { + integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==, + } + engines: { node: ">=10" } + + parent-module@1.0.1: + resolution: { + integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==, + } + engines: { node: ">=6" } + + path-exists@4.0.0: + resolution: { + integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==, + } + engines: { node: ">=8" } + + path-key@3.1.1: + resolution: { + integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==, + } + engines: { node: ">=8" } + + path-parse@1.0.7: + resolution: { + integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==, + } + + picomatch@2.3.1: + resolution: { + integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==, + } + engines: { node: ">=8.6" } + + picomatch@4.0.3: + resolution: { + integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==, + } + engines: { node: ">=12" } + + prelude-ls@1.2.1: + resolution: { + integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==, + } + engines: { node: ">= 0.8.0" } + + punycode@2.3.1: + resolution: { + integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==, + } + engines: { node: ">=6" } + + pure-rand@6.1.0: + resolution: { + integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==, + } + + resolve-from@4.0.0: + resolution: { + integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==, + } + engines: { node: ">=4" } + + resolve@1.22.11: + resolution: { + integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==, + } + engines: { node: ">= 0.4" } + hasBin: true + + semver@7.7.4: + resolution: { + integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==, + } + engines: { node: ">=10" } + hasBin: true + + shebang-command@2.0.0: + resolution: { + integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==, + } + engines: { node: ">=8" } + + shebang-regex@3.0.0: + resolution: { + integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==, + } + engines: { node: ">=8" } + + source-map@0.6.1: + resolution: { + integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==, + } + engines: { node: ">=0.10.0" } + + strip-json-comments@3.1.1: + resolution: { + integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==, + } + engines: { node: ">=8" } + + supports-color@7.2.0: + resolution: { + integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==, + } + engines: { node: ">=8" } + + supports-preserve-symlinks-flag@1.0.0: + resolution: { + integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==, + } + engines: { node: ">= 0.4" } + + tinyglobby@0.2.15: + resolution: { + integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==, + } + engines: { node: ">=12.0.0" } + + to-regex-range@5.0.1: + resolution: { + integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==, + } + engines: { node: ">=8.0" } + + ts-api-utils@2.4.0: + resolution: { + integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==, + } + engines: { node: ">=18.12" } + peerDependencies: + typescript: ">=4.8.4" + + ts-declaration-location@1.0.7: + resolution: { + integrity: sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==, + } + peerDependencies: + typescript: ">=4.0.0" + + type-check@0.4.0: + resolution: { + integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==, + } + engines: { node: ">= 0.8.0" } + + typescript@5.9.3: + resolution: { + integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==, + } + engines: { node: ">=14.17" } + hasBin: true + + uglify-js@3.19.3: + resolution: { + integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==, + } + engines: { node: ">=0.8.0" } + hasBin: true + + undici-types@7.18.2: + resolution: { + integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==, + } + + uri-js@4.4.1: + resolution: { + integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==, + } + + which@2.0.2: + resolution: { + integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==, + } + engines: { node: ">= 8" } + hasBin: true + + word-wrap@1.2.5: + resolution: { + integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==, + } + engines: { node: ">=0.10.0" } + + wordwrap@1.0.0: + resolution: { + integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==, + } + + yocto-queue@0.1.0: + resolution: { + integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==, + } + engines: { node: ">=10" } + +snapshots: + "@boundaries/elements@1.2.0(eslint@9.39.4)": + dependencies: + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.1(eslint-import-resolver-node@0.3.9)(eslint@9.39.4) + handlebars: 4.7.8 + is-core-module: 2.16.1 + micromatch: 4.0.8 + transitivePeerDependencies: + - "@typescript-eslint/parser" + - eslint + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + "@eslint-community/eslint-utils@4.9.1(eslint@9.39.4)": + dependencies: + eslint: 9.39.4 + eslint-visitor-keys: 3.4.3 + + "@eslint-community/regexpp@4.12.2": {} + + "@eslint/config-array@0.21.2": + dependencies: + "@eslint/object-schema": 2.1.7 + debug: 4.4.3 + minimatch: 3.1.5 + transitivePeerDependencies: + - supports-color + + "@eslint/config-helpers@0.4.2": + dependencies: + "@eslint/core": 0.17.0 + + "@eslint/core@0.17.0": + dependencies: + "@types/json-schema": 7.0.15 + + "@eslint/eslintrc@3.3.5": + dependencies: + ajv: 6.14.0 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.5 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + "@eslint/js@9.39.4": {} + + "@eslint/object-schema@2.1.7": {} + + "@eslint/plugin-kit@0.4.1": + dependencies: + "@eslint/core": 0.17.0 + levn: 0.4.1 + + "@humanfs/core@0.19.1": {} + + "@humanfs/node@0.16.7": + dependencies: + "@humanfs/core": 0.19.1 + "@humanwhocodes/retry": 0.4.3 + + "@humanwhocodes/module-importer@1.0.1": {} + + "@humanwhocodes/retry@0.4.3": {} + + "@oxlint-tsgolint/darwin-arm64@0.16.0": + optional: true + + "@oxlint-tsgolint/darwin-x64@0.16.0": + optional: true + + "@oxlint-tsgolint/linux-arm64@0.16.0": + optional: true + + "@oxlint-tsgolint/linux-x64@0.16.0": + optional: true + + "@oxlint-tsgolint/win32-arm64@0.16.0": + optional: true + + "@oxlint-tsgolint/win32-x64@0.16.0": + optional: true + + "@oxlint/binding-android-arm-eabi@1.55.0": + optional: true + + "@oxlint/binding-android-arm64@1.55.0": + optional: true + + "@oxlint/binding-darwin-arm64@1.55.0": + optional: true + + "@oxlint/binding-darwin-x64@1.55.0": + optional: true + + "@oxlint/binding-freebsd-x64@1.55.0": + optional: true + + "@oxlint/binding-linux-arm-gnueabihf@1.55.0": + optional: true + + "@oxlint/binding-linux-arm-musleabihf@1.55.0": + optional: true + + "@oxlint/binding-linux-arm64-gnu@1.55.0": + optional: true + + "@oxlint/binding-linux-arm64-musl@1.55.0": + optional: true + + "@oxlint/binding-linux-ppc64-gnu@1.55.0": + optional: true + + "@oxlint/binding-linux-riscv64-gnu@1.55.0": + optional: true + + "@oxlint/binding-linux-riscv64-musl@1.55.0": + optional: true + + "@oxlint/binding-linux-s390x-gnu@1.55.0": + optional: true + + "@oxlint/binding-linux-x64-gnu@1.55.0": + optional: true + + "@oxlint/binding-linux-x64-musl@1.55.0": + optional: true + + "@oxlint/binding-openharmony-arm64@1.55.0": + optional: true + + "@oxlint/binding-win32-arm64-msvc@1.55.0": + optional: true + + "@oxlint/binding-win32-ia32-msvc@1.55.0": + optional: true + + "@oxlint/binding-win32-x64-msvc@1.55.0": + optional: true + + "@types/bun@1.3.10": + dependencies: + bun-types: 1.3.10 + + "@types/estree@1.0.8": {} + + "@types/json-schema@7.0.15": {} + + "@types/node@25.5.0": + dependencies: + undici-types: 7.18.2 + + "@typescript-eslint/project-service@8.57.0(typescript@5.9.3)": + dependencies: + "@typescript-eslint/tsconfig-utils": 8.57.0(typescript@5.9.3) + "@typescript-eslint/types": 8.57.0 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/scope-manager@8.57.0": + dependencies: + "@typescript-eslint/types": 8.57.0 + "@typescript-eslint/visitor-keys": 8.57.0 + + "@typescript-eslint/tsconfig-utils@8.57.0(typescript@5.9.3)": + dependencies: + typescript: 5.9.3 + + "@typescript-eslint/type-utils@8.57.0(eslint@9.39.4)(typescript@5.9.3)": + dependencies: + "@typescript-eslint/types": 8.57.0 + "@typescript-eslint/typescript-estree": 8.57.0(typescript@5.9.3) + "@typescript-eslint/utils": 8.57.0(eslint@9.39.4)(typescript@5.9.3) + debug: 4.4.3 + eslint: 9.39.4 + ts-api-utils: 2.4.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/types@8.57.0": {} + + "@typescript-eslint/typescript-estree@8.57.0(typescript@5.9.3)": + dependencies: + "@typescript-eslint/project-service": 8.57.0(typescript@5.9.3) + "@typescript-eslint/tsconfig-utils": 8.57.0(typescript@5.9.3) + "@typescript-eslint/types": 8.57.0 + "@typescript-eslint/visitor-keys": 8.57.0 + debug: 4.4.3 + minimatch: 10.2.4 + semver: 7.7.4 + tinyglobby: 0.2.15 + ts-api-utils: 2.4.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/utils@8.57.0(eslint@9.39.4)(typescript@5.9.3)": + dependencies: + "@eslint-community/eslint-utils": 4.9.1(eslint@9.39.4) + "@typescript-eslint/scope-manager": 8.57.0 + "@typescript-eslint/types": 8.57.0 + "@typescript-eslint/typescript-estree": 8.57.0(typescript@5.9.3) + eslint: 9.39.4 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/visitor-keys@8.57.0": + dependencies: + "@typescript-eslint/types": 8.57.0 + eslint-visitor-keys: 5.0.1 + + acorn-jsx@5.3.2(acorn@8.16.0): + dependencies: + acorn: 8.16.0 + + acorn@8.16.0: {} + + ajv@6.14.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + argparse@2.0.1: {} + + balanced-match@1.0.2: {} + + balanced-match@4.0.4: {} + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@5.0.4: + dependencies: + balanced-match: 4.0.4 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + bun-types@1.3.10: + dependencies: + "@types/node": 25.5.0 + + callsites@3.1.0: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + concat-map@0.0.1: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + deepmerge-ts@7.1.5: {} + + escape-string-regexp@4.0.0: {} + + escape-string-regexp@5.0.0: {} + + eslint-import-resolver-node@0.3.9: + dependencies: + debug: 3.2.7 + is-core-module: 2.16.1 + resolve: 1.22.11 + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.1(eslint-import-resolver-node@0.3.9)(eslint@9.39.4): + dependencies: + debug: 3.2.7 + optionalDependencies: + eslint: 9.39.4 + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + + eslint-plugin-boundaries@5.4.0(eslint@9.39.4): + dependencies: + "@boundaries/elements": 1.2.0(eslint@9.39.4) + chalk: 4.1.2 + eslint: 9.39.4 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.1(eslint-import-resolver-node@0.3.9)(eslint@9.39.4) + micromatch: 4.0.8 + transitivePeerDependencies: + - "@typescript-eslint/parser" + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-functional@9.0.4(eslint@9.39.4)(typescript@5.9.3): + dependencies: + "@typescript-eslint/utils": 8.57.0(eslint@9.39.4)(typescript@5.9.3) + deepmerge-ts: 7.1.5 + escape-string-regexp: 5.0.0 + eslint: 9.39.4 + is-immutable-type: 5.0.1(eslint@9.39.4)(typescript@5.9.3) + ts-api-utils: 2.4.0(typescript@5.9.3) + ts-declaration-location: 1.0.7(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + eslint-plugin-oxlint@1.55.0: + dependencies: + jsonc-parser: 3.3.1 + + eslint-plugin-prefer-arrow-functions@3.9.1(eslint@9.39.4)(typescript@5.9.3): + dependencies: + "@typescript-eslint/types": 8.57.0 + "@typescript-eslint/utils": 8.57.0(eslint@9.39.4)(typescript@5.9.3) + eslint: 9.39.4 + transitivePeerDependencies: + - supports-color + - typescript + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint-visitor-keys@5.0.1: {} + + eslint@9.39.4: + dependencies: + "@eslint-community/eslint-utils": 4.9.1(eslint@9.39.4) + "@eslint-community/regexpp": 4.12.2 + "@eslint/config-array": 0.21.2 + "@eslint/config-helpers": 0.4.2 + "@eslint/core": 0.17.0 + "@eslint/eslintrc": 3.3.5 + "@eslint/js": 9.39.4 + "@eslint/plugin-kit": 0.4.1 + "@humanfs/node": 0.16.7 + "@humanwhocodes/module-importer": 1.0.1 + "@humanwhocodes/retry": 0.4.3 + "@types/estree": 1.0.8 + ajv: 6.14.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + fast-check@3.23.2: + dependencies: + pure-rand: 6.1.0 + + fast-deep-equal@3.1.3: {} + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.4.1 + keyv: 4.5.4 + + flatted@3.4.1: {} + + function-bind@1.1.2: {} + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@14.0.0: {} + + handlebars@4.7.8: + dependencies: + minimist: 1.2.8 + neo-async: 2.6.2 + source-map: 0.6.1 + wordwrap: 1.0.0 + optionalDependencies: + uglify-js: 3.19.3 + + has-flag@4.0.0: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + ignore@5.3.2: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-immutable-type@5.0.1(eslint@9.39.4)(typescript@5.9.3): + dependencies: + "@typescript-eslint/type-utils": 8.57.0(eslint@9.39.4)(typescript@5.9.3) + eslint: 9.39.4 + ts-api-utils: 2.4.0(typescript@5.9.3) + ts-declaration-location: 1.0.7(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + is-number@7.0.0: {} + + isexe@2.0.0: {} + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + jsonc-parser@3.3.1: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + minimatch@10.2.4: + dependencies: + brace-expansion: 5.0.4 + + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.12 + + minimist@1.2.8: {} + + ms@2.1.3: {} + + natural-compare@1.4.0: {} + + neo-async@2.6.2: {} + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + oxlint-tsgolint@0.16.0: + optionalDependencies: + "@oxlint-tsgolint/darwin-arm64": 0.16.0 + "@oxlint-tsgolint/darwin-x64": 0.16.0 + "@oxlint-tsgolint/linux-arm64": 0.16.0 + "@oxlint-tsgolint/linux-x64": 0.16.0 + "@oxlint-tsgolint/win32-arm64": 0.16.0 + "@oxlint-tsgolint/win32-x64": 0.16.0 + + oxlint@1.55.0(oxlint-tsgolint@0.16.0): + optionalDependencies: + "@oxlint/binding-android-arm-eabi": 1.55.0 + "@oxlint/binding-android-arm64": 1.55.0 + "@oxlint/binding-darwin-arm64": 1.55.0 + "@oxlint/binding-darwin-x64": 1.55.0 + "@oxlint/binding-freebsd-x64": 1.55.0 + "@oxlint/binding-linux-arm-gnueabihf": 1.55.0 + "@oxlint/binding-linux-arm-musleabihf": 1.55.0 + "@oxlint/binding-linux-arm64-gnu": 1.55.0 + "@oxlint/binding-linux-arm64-musl": 1.55.0 + "@oxlint/binding-linux-ppc64-gnu": 1.55.0 + "@oxlint/binding-linux-riscv64-gnu": 1.55.0 + "@oxlint/binding-linux-riscv64-musl": 1.55.0 + "@oxlint/binding-linux-s390x-gnu": 1.55.0 + "@oxlint/binding-linux-x64-gnu": 1.55.0 + "@oxlint/binding-linux-x64-musl": 1.55.0 + "@oxlint/binding-openharmony-arm64": 1.55.0 + "@oxlint/binding-win32-arm64-msvc": 1.55.0 + "@oxlint/binding-win32-ia32-msvc": 1.55.0 + "@oxlint/binding-win32-x64-msvc": 1.55.0 + oxlint-tsgolint: 0.16.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + prelude-ls@1.2.1: {} + + punycode@2.3.1: {} + + pure-rand@6.1.0: {} + + resolve-from@4.0.0: {} + + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + semver@7.7.4: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + source-map@0.6.1: {} + + strip-json-comments@3.1.1: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + ts-api-utils@2.4.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + ts-declaration-location@1.0.7(typescript@5.9.3): + dependencies: + picomatch: 4.0.3 + typescript: 5.9.3 + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typescript@5.9.3: {} + + uglify-js@3.19.3: + optional: true + + undici-types@7.18.2: {} + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wordwrap@1.0.0: {} + + yocto-queue@0.1.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..3334c0e --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1 @@ +packages: [] diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000..2196351 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,70 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "plugins": [ + { + "type": "cargo-workspace" + }, + { + "type": "linked-versions", + "groupName": "parser-group", + "components": [ + "parser", + "wasm-javascript", + "wasm-wasi", + "spec" + ] + } + ], + "release-type": "rust", + "bump-minor-pre-major": true, + "bump-patch-for-minor-pre-major": true, + "separate-pull-requests": false, + "include-component-in-tag": true, + "include-v-in-tag": true, + "tag-separator": "-", + "packages": { + "parser": { + "release-type": "rust", + "component": "parser" + }, + "wasm-javascript": { + "release-type": "rust", + "component": "wasm-javascript" + }, + "wasm-wasi": { + "release-type": "rust", + "component": "wasm-wasi" + }, + "spec": { + "release-type": "simple", + "component": "spec" + }, + "riff-cli": { + "path": "riff-cli", + "release-type": "rust", + "component": "riff" + }, + "slash-rust": { + "release-type": "rust", + "component": "slash-rust" + }, + "slash-javascript": { + "release-type": "node", + "component": "slash-javascript" + }, + "slash-web": { + "release-type": "node", + "component": "slash-web" + }, + "slash-python": { + "release-type": "python", + "component": "slash-python" + }, + "slash-go": { + "release-type": "go", + "component": "slash-go", + "tag-separator": "/", + "include-v-in-tag": true + } + } +} diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..8762f16 --- /dev/null +++ b/renovate.json @@ -0,0 +1,42 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended" + ], + "labels": [ + "dependencies" + ], + "packageRules": [ + { + "matchManagers": [ + "cargo" + ], + "groupName": "rust dependencies" + }, + { + "matchManagers": [ + "pnpm" + ], + "groupName": "pnpm dependencies" + }, + { + "matchManagers": [ + "pip_requirements", + "poetry" + ], + "groupName": "python dependencies" + }, + { + "matchManagers": [ + "gomod" + ], + "groupName": "go dependencies" + }, + { + "matchManagers": [ + "github-actions" + ], + "groupName": "github actions" + } + ] +} diff --git a/riff-cli/.goreleaser.yaml b/riff-cli/.goreleaser.yaml new file mode 100644 index 0000000..fa39f6d --- /dev/null +++ b/riff-cli/.goreleaser.yaml @@ -0,0 +1,101 @@ +# yaml-language-server: $schema=https://goreleaser.com/static/schema.json +version: 2 + +project_name: riff + +release: + mode: keep-existing + github: + owner: tomdavidson + name: slasher + +changelog: + disable: true + +before: + hooks: + - rustup default stable + - cargo install --locked cargo-zigbuild + +builds: + - id: riff + builder: rust + dir: riff-cli + targets: + - x86_64-unknown-linux-gnu + - aarch64-unknown-linux-gnu + - x86_64-apple-darwin + - aarch64-apple-darwin + env: + - RUSTFLAGS=-C target-feature=+crt-static + +archives: + - id: riff-archives + builds: + - riff + format: tar.gz + name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" + files: + - LICENSE* + - README* + +nfpms: + - id: riff-nfpms + package_name: riff + file_name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" + formats: + - deb + - rpm + - apk + builds: + - riff + maintainer: "Tom Davidson " + description: "Slasher riff CLI — slash command parser" + license: MIT + homepage: "https://github.com/tomdavidson/slasher" + +brews: + - name: riff + ids: + - riff-archives + repository: + owner: tomdavidson + name: homebrew-tap + token: "{{ .Env.HOMEBREW_TAP_TOKEN }}" + directory: Formula + homepage: "https://github.com/tomdavidson/slasher" + description: "Slasher riff CLI — slash command parser" + license: MIT + +dockers: + - image_templates: + - "ghcr.io/tomdavidson/riff:{{ .Version }}-amd64" + use: buildx + goos: linux + goarch: amd64 + dockerfile: riff-cli/Dockerfile + build_flag_templates: + - "--platform=linux/amd64" + - image_templates: + - "ghcr.io/tomdavidson/riff:{{ .Version }}-arm64" + use: buildx + goos: linux + goarch: arm64 + dockerfile: riff-cli/Dockerfile + build_flag_templates: + - "--platform=linux/arm64" + +docker_manifests: + - name_template: "ghcr.io/tomdavidson/riff:{{ .Version }}" + image_templates: + - "ghcr.io/tomdavidson/riff:{{ .Version }}-amd64" + - "ghcr.io/tomdavidson/riff:{{ .Version }}-arm64" + - name_template: "ghcr.io/tomdavidson/riff:latest" + image_templates: + - "ghcr.io/tomdavidson/riff:{{ .Version }}-amd64" + - "ghcr.io/tomdavidson/riff:{{ .Version }}-arm64" + +checksum: + name_template: "{{ .ProjectName }}_checksums.txt" + +dist: dist diff --git a/riff-cli/Dockerfile b/riff-cli/Dockerfile new file mode 100644 index 0000000..717fb85 --- /dev/null +++ b/riff-cli/Dockerfile @@ -0,0 +1,3 @@ +FROM gcr.io/distroless/static:nonroot +COPY riff /usr/local/bin/riff +ENTRYPOINT ["/usr/local/bin/riff"] diff --git a/riff-cli/moon.yml b/riff-cli/moon.yml index 1d3fc95..eb1fe02 100644 --- a/riff-cli/moon.yml +++ b/riff-cli/moon.yml @@ -1,6 +1,7 @@ $schema: "https://moonrepo.dev/schemas/project.json" id: "riff-cli" language: "rust" + tags: ["cli"] workspace: @@ -39,3 +40,4 @@ workspace: # # We don't depend on docker-login here, because snapshots don't push to GHCR! # deps: # - 'parser:build' + diff --git a/scripts/gen-workflows.sh b/scripts/gen-workflows.sh new file mode 100755 index 0000000..a7e5b30 --- /dev/null +++ b/scripts/gen-workflows.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail + +# TODO: Generate publish workflows from Moon Tera templates +# Once .moon/templates/publish-workflows/ is implemented, this script will: +# moon generate publish-workflows --force +# and place generated files into .github/workflows/ +# +# For now, publish workflows are hand-authored under .github/workflows/publish-*.yml +# To add a new SDK publish workflow, copy an existing one and adjust the tag prefix, +# project name, and publish command. + +echo "Workflow generation not yet implemented — publish workflows are hand-authored." +echo "See .github/workflows/publish-*.yml" diff --git a/slash-go/moon.yml b/slash-go/moon.yml index c9a0d75..4980cfe 100644 --- a/slash-go/moon.yml +++ b/slash-go/moon.yml @@ -1,9 +1,4 @@ -# $schema: https://moonrepo.dev/schemas/project.json - -language: "unknown" - -tags: ["core"] - -workspace: - inheritedTasks: - include: [] +$schema: "https://moonrepo.dev/schemas/project.json" +language: "go" +type: "library" +tags: ["sdk"] diff --git a/slash-javascript/moon.yml b/slash-javascript/moon.yml index c9a0d75..75ba71a 100644 --- a/slash-javascript/moon.yml +++ b/slash-javascript/moon.yml @@ -1,9 +1,11 @@ -# $schema: https://moonrepo.dev/schemas/project.json +$schema: "https://moonrepo.dev/schemas/project.json" +language: "typescript" +type: "library" +tags: ["sdk", "npm"] -language: "unknown" - -tags: ["core"] - -workspace: - inheritedTasks: - include: [] +tasks: + publish: + command: "pnpm" + args: ["publish", "--access", "public", "--no-git-checks"] + options: + runInCI: false diff --git a/slash-python/moon.yml b/slash-python/moon.yml index c9a0d75..c58c0fc 100644 --- a/slash-python/moon.yml +++ b/slash-python/moon.yml @@ -1,9 +1,11 @@ -# $schema: https://moonrepo.dev/schemas/project.json +$schema: "https://moonrepo.dev/schemas/project.json" +language: "python" +type: "library" +tags: ["sdk"] -language: "unknown" - -tags: ["core"] - -workspace: - inheritedTasks: - include: [] +tasks: + publish: + command: "python" + args: ["-m", "twine", "upload", "dist/*"] + options: + runInCI: false diff --git a/slash-rust/moon.yml b/slash-rust/moon.yml index c9a0d75..eb08538 100644 --- a/slash-rust/moon.yml +++ b/slash-rust/moon.yml @@ -1,9 +1,11 @@ -# $schema: https://moonrepo.dev/schemas/project.json +$schema: "https://moonrepo.dev/schemas/project.json" +language: "rust" +type: "library" +tags: ["sdk"] -language: "unknown" - -tags: ["core"] - -workspace: - inheritedTasks: - include: [] +tasks: + publish: + command: "cargo" + args: ["publish", "--allow-dirty"] + options: + runInCI: false diff --git a/slash-web/moon.yml b/slash-web/moon.yml index c9a0d75..75ba71a 100644 --- a/slash-web/moon.yml +++ b/slash-web/moon.yml @@ -1,9 +1,11 @@ -# $schema: https://moonrepo.dev/schemas/project.json +$schema: "https://moonrepo.dev/schemas/project.json" +language: "typescript" +type: "library" +tags: ["sdk", "npm"] -language: "unknown" - -tags: ["core"] - -workspace: - inheritedTasks: - include: [] +tasks: + publish: + command: "pnpm" + args: ["publish", "--access", "public", "--no-git-checks"] + options: + runInCI: false diff --git a/wasm-javascript/moon.yml b/wasm-javascript/moon.yml index c9a0d75..3263f79 100644 --- a/wasm-javascript/moon.yml +++ b/wasm-javascript/moon.yml @@ -1,9 +1,4 @@ -# $schema: https://moonrepo.dev/schemas/project.json - -language: "unknown" - -tags: ["core"] - -workspace: - inheritedTasks: - include: [] +$schema: "https://moonrepo.dev/schemas/project.json" +language: "rust" +type: "library" +tags: ["wasm"] diff --git a/wasm-javascript/scripts/attach-release-assets.sh b/wasm-javascript/scripts/attach-release-assets.sh new file mode 100755 index 0000000..23fa8ea --- /dev/null +++ b/wasm-javascript/scripts/attach-release-assets.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Attach wasm-javascript build artifacts to the current GitHub Release +# Run from repo root. Expects GITHUB_TOKEN and GITHUB_REF_NAME to be set. + +artifact_dir="wasm-javascript/pkg" + +if [ ! -d "$artifact_dir" ]; then + echo "ERROR: Build output directory $artifact_dir not found" + exit 1 +fi + +for file in "$artifact_dir"/*; do + [ -f "$file" ] || continue + name="$(basename "$file")" + echo "Uploading $name" + gh release upload "$GITHUB_REF_NAME" "$file" --repo "$GITHUB_REPOSITORY" --clobber +done diff --git a/wasm-wasi/moon.yml b/wasm-wasi/moon.yml index c9a0d75..3263f79 100644 --- a/wasm-wasi/moon.yml +++ b/wasm-wasi/moon.yml @@ -1,9 +1,4 @@ -# $schema: https://moonrepo.dev/schemas/project.json - -language: "unknown" - -tags: ["core"] - -workspace: - inheritedTasks: - include: [] +$schema: "https://moonrepo.dev/schemas/project.json" +language: "rust" +type: "library" +tags: ["wasm"] diff --git a/wasm-wasi/scripts/attach-release-assets.sh b/wasm-wasi/scripts/attach-release-assets.sh new file mode 100755 index 0000000..b7c5b34 --- /dev/null +++ b/wasm-wasi/scripts/attach-release-assets.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Attach wasm-wasi + WIT artifacts to the current GitHub Release +# Run from repo root. Expects GITHUB_TOKEN and GITHUB_REF_NAME to be set. + +wasm_dir="wasm-wasi/target/wasm32-wasip2/release" +wit_dir="wasm-wasi/wit" + +# Upload WASM component if built +if [ -d "$wasm_dir" ]; then + for file in "$wasm_dir"/*.wasm; do + [ -f "$file" ] || continue + echo "Uploading $(basename "$file")" + gh release upload "$GITHUB_REF_NAME" "$file" --repo "$GITHUB_REPOSITORY" --clobber + done +else + echo "WARN: WASM build output directory $wasm_dir not found" +fi + +# Upload WIT definitions +if [ -d "$wit_dir" ]; then + for file in "$wit_dir"/*.wit; do + [ -f "$file" ] || continue + echo "Uploading $(basename "$file")" + gh release upload "$GITHUB_REF_NAME" "$file" --repo "$GITHUB_REPOSITORY" --clobber + done + + # Also create a bundled wit archive + tar -czf wit-definitions.tar.gz -C wasm-wasi wit/ + gh release upload "$GITHUB_REF_NAME" "wit-definitions.tar.gz" --repo "$GITHUB_REPOSITORY" --clobber + rm -f wit-definitions.tar.gz +else + echo "WARN: WIT directory $wit_dir not found" +fi diff --git a/website/moon.yml b/website/moon.yml index c9a0d75..d2ebd6b 100644 --- a/website/moon.yml +++ b/website/moon.yml @@ -1,8 +1,7 @@ -# $schema: https://moonrepo.dev/schemas/project.json - -language: "unknown" - -tags: ["core"] +$schema: "https://moonrepo.dev/schemas/project.json" +language: "typescript" +type: "application" +tags: ["docs"] workspace: inheritedTasks: