diff --git a/plans/refactor/PLAN.md b/plans/refactor/PLAN.md deleted file mode 100644 index 633f222..0000000 --- a/plans/refactor/PLAN.md +++ /dev/null @@ -1,418 +0,0 @@ -# Refactor epic plan: smart detection + domain architecture - -## Objective - -Refactor `matrixai-lint` into a domain-oriented lint engine that: - -- Performs smart auto-discovery (project relevance) independently from tool availability. -- Distinguishes built-in npm-based capabilities (for example ESLint/Prettier) from optional external tools (for example ShellCheck). -- Supports explicit domain selection (include/exclude/only) with consistent target semantics. -- Provides clear built-in domain boundaries and downstream ESLint extensibility via config composition. - -## Non-goals - -- No behavior-changing implementation in this epic document (this is design/spec only). -- No changes to the shipped ESLint ruleset content (rule tuning is out of scope). -- No attempt to fully replace ESLint/Prettier/ShellCheck; this project orchestrates them. - -## Constraints / invariants - -- Must remain usable downstream via `matrixai-lint` and `matrixai-lint --fix`. -- Built-in JS/TS linting and Markdown formatting must work with only npm dependencies installed. -- External-tool domains must be safe to auto-skip when tools are absent, unless explicitly requested. -- No edits to non-markdown source files in this subtask. - -## Docs map - -- [`PLAN.md`](PLAN.md): design/spec and phased refactor plan. -- [`STATE.md`](STATE.md): current state, open questions, next actions. - -## Decomposition rule - -If this plan grows beyond a workable single-document size, split into numbered docs (for example `10-cli.md`, `20-config.md`) and keep [`PLAN.md`](PLAN.md) as the index. - -## Current reality lives in - -- [`STATE.md`](STATE.md) - ---- - -## Problem statement - -Current `matrixai-lint` behavior (as implemented today) has several structural issues: - -- **Fixed domain sequence**: ESLint then shellcheck then Markdown/Prettier; users cannot explicitly select domains. -- **Targeting does not imply selection**: `--eslint` narrows ESLint scope but does not prevent other domains from running. -- **Inconsistent shell semantics**: `--shell` is described as glob(s) but is treated as existing search roots/paths. -- **Default scope is overly coupled** to `cwd` and a single `tsconfig`-driven include/exclude interpretation. -- **Extensibility constraints**: no clean, explicit domain interface; adding domains requires cross-cutting changes. -- **Missing-tool behavior** is ad-hoc: optional external tools are not modeled as first-class capabilities. -- **Unknown options are silently ignored** instead of failing fast, making typos and accidental misuse hard to detect. -- **Multi-tsconfig behavior is inconsistent**: target pattern derivation and parser project inputs are not aligned. -- **Error aggregation is fragile**: an early return path can mask already-recorded failures, and thrown domain errors can bypass unified summary output. -- **Glob synthesis can be malformed** when tsconfig include entries already carry file extensions and wrapper logic appends another extension suffix. -- **Repo scripts bias exercised behavior** by always passing both ESLint and shell roots, so domain-only workflows are under-validated. - -Downstream impact: consumers may not have optional external tools installed, but should still get reliable built-in linting/formatting. - -## Design goals - -1. **Make domains first-class**: discover, select, configure, run, and report per domain. -2. **Separate relevance from availability**: do not confuse "this repo has shell scripts" with "shellcheck exists". -3. **Consistent targeting**: every domain must interpret targets the same way (paths/globs anchored at a well-defined root). -4. **Predictable missing-tool semantics**: optional tools skip with warning when auto-selected, but fail when explicitly requested. -5. **Backwards compatibility**: preserve the common experience for `matrixai-lint` and `matrixai-lint --fix`, while enabling a richer CLI. -6. **Extensibility**: add domains without modifying core orchestration logic. -7. **Deterministic failure reporting**: always aggregate and summarize all executed-domain outcomes with no silent success paths. -8. **Strict option correctness**: unknown flags must fail by default with actionable diagnostics. -9. **Multi-project correctness**: file targeting and parser project configuration must be aligned for all configured tsconfig entries. - ---- - -## Smart detection model: project relevance vs tool availability - -Each domain evaluation is the product of two independent assessments: - -### 1) Project relevance - -"Should we lint/format this domain in this project (or this target set)?" - -Examples of relevance signals: - -- ESLint (JS/TS): any `*.{js,mjs,cjs,jsx,ts,tsx,mts,cts,json}` in the target set. -- Markdown/Prettier: any `*.{md,mdx}` in the target set (plus `README.md` by convention). -- ShellCheck: any `*.sh` in the target set. - -Relevance must be computed against the *effective target set* (CLI paths/globs + config defaults), not against the whole filesystem blindly. - -### 2) Tool availability - -"Do we have the tools required to run this domain right now?" - -Availability is domain-specific: - -- **Built-in npm-based** domains (ESLint, Prettier) are expected to be available whenever `@matrixai/lint` is installed. -- **External optional** domains (ShellCheck) may not exist in downstream environments. - -### Decision matrix - -- If **relevant + available**: run domain. -- If **relevant + unavailable**: - - If domain was **auto-selected**: skip with warning. - - If domain was **explicitly requested**: fail with a "missing tool" error. -- If **not relevant**: - - If auto-selected: skip silently (or with `--verbose` explain). - - If explicitly requested: run as a no-op that reports "no files matched" (default success), unless a domain opts into strictness. - -This model explicitly distinguishes "capability exists" from "domain matters". - ---- - -## Proposed domain architecture - -### High-level components - -- **Lint engine**: parses CLI/config, computes target set, selects domains, orchestrates execution, aggregates results. -- **Domain modules**: encapsulate discovery, tool checks, execution, and reporting for one domain. -- **Capability registry**: standardizes dependency checks (npm module resolution vs external binary lookup). - -### Domain module interface (conceptual) - -Each domain module should define: - -- `id`: stable string identifier (for example `eslint`, `shellcheck`). -- `discover(ctx)`: returns relevance result and default target patterns for this domain. -- `dependencies(ctx)`: declares required and optional dependencies. -- `run(ctx, targets, mode)`: executes the domain toolchain and returns a normalized result. -- `supportsFix`: whether `--fix` can be applied. - -The engine is responsible for: - -- Converting CLI/config selection into a domain run list. -- Applying the missing-tool policy based on dependency classification and explicit request state. -- Rendering consistent output and a final exit code. - -### Built-in domains (minimum) - -1. **eslint** - - Built-in npm-based capability. - - Type-aware TS linting when tsconfig information is available. -2. **markdown-prettier** - - Built-in npm-based capability. - - Formats/checks Markdown and MDX. -3. **shellcheck** - - External optional tool. - - Lints `*.sh`. - -### Mermaid: selection and execution pipeline - -```mermaid -flowchart TD - A[CLI args and config] --> B[Resolve root and targets] - B --> C[Discover relevance per domain] - B --> D[Check tool availability per domain] - C --> E[Select domains based on include and exclude] - D --> E - E --> F[Run domains in defined order] - F --> G[Aggregate results and exit] -``` - ---- - -## Dependency classification and missing-tool semantics - -### Dependency categories - -Dependencies are classified at evaluation time: - -1. **Required** - - Always required for a domain to run. - - Missing is a fatal error. - - Example: ESLint runtime modules for the `eslint` domain. - -2. **Optional** - - Not required for the overall command when the domain is auto-selected. - - Missing results in a skip-with-warning. - - Example: `shellcheck` binary for the `shellcheck` domain. - -3. **Explicitly-requested-required** - - Any optional dependency becomes required if the user explicitly requests the domain. - - Missing results in a fatal error with clear remediation. - -### Policy rules - -- **Auto-discovery must never fail the command** due solely to missing optional external tools. -- **Explicit domain selection must be strict**: if a user asks for `shellcheck`, and the tool is missing, exit non-zero. -- Provide an actionable error message (what is missing, how the tool was detected, how to install). - ---- - -## New CLI model: targeted linting + domain inclusion/exclusion - -### Proposed flags (vNext) - -Core: - -- `matrixai-lint [targets...]` where `targets` are paths and/or globs. -- `--fix` apply fixes for domains that support fixes. -- `--domain ` run only these domains (explicit request). -- `--skip-domain ` exclude domains from auto-run. -- `--list-domains` print available domain IDs and brief descriptions. -- `--explain` print why each domain ran or was skipped (relevance and availability). - -ESLint-specific (kept, but clarified): - -- `--eslint ` override ESLint targets (implicitly requests the `eslint` domain). -- `--eslint-config ` explicit ESLint config override (alias: legacy `--config`). -- `--user-config` keep current meaning for ESLint config discovery. - -ShellCheck-specific: - -- `--shell ` rename or redefine in a consistent way. - - Preferred: treat values as targets (same as positional targets) and match `*.sh` within them. - - Back-compat: if values are directories, treat as roots; if globs, expand to files. - -Markdown/Prettier-specific: - -- Optional future: `--markdown ` to override markdown targets. - -Nixfmt-specific: - -- Optional future: `--nix ` to override nix targets. - -### Selection precedence - -1. If `--domain` is provided: run only those domains (strict missing-tool behavior). -2. Else: auto-discover relevant domains. -3. Apply `--skip-domain` exclusions. -4. Domain-specific target overrides (for example `--eslint`, `--shell`) implicitly request that domain even if relevance would be otherwise false. - -### Unknown option policy and pass-through model - -- Default behavior should reject unknown CLI options with usage/config error exit (`2`). -- Wrapper-level pass-through should not rely on silent unknown-option acceptance. -- If pass-through is needed, introduce explicit scoped flags (for example domain-specific extra args) instead of blanket unknown forwarding. -- During migration, unknown options can emit deprecation warnings for one release window before strict rejection is enforced. - ---- - -## Config schema proposal (v2) + examples - -### File discovery - -Continue to support `matrixai-lint-config.json`, but evolve it to a versioned schema. - -- If `version` is absent: treat as v1 (today) with top-level `tsconfigPaths` and `forceInclude`. -- If `version: 2`: enable the domain-aware schema. - -### v2 shape (conceptual) - -```json -{ - "version": 2, - "root": ".", - "defaults": { - "targets": ["."], - "ignore": ["node_modules/**", "dist/**"] - }, - "domains": { - "eslint": { - "enabled": "auto", - "tsconfigPaths": ["./tsconfig.json"], - "forceInclude": ["scripts"], - "config": { - "useUserConfig": false, - "overrideConfigPath": null - } - }, - "markdown-prettier": { - "enabled": "auto", - "targets": ["README.md", "docs/**/*.{md,mdx}"] - }, - "shellcheck": { - "enabled": "auto", - "targets": ["src/**/*.sh", "scripts/**/*.sh", "tests/**/*.sh"], - "tool": { - "command": "shellcheck" - } - } - } -} -``` - -Notes: - -- `enabled` supports: `auto` | `on` | `off`. -- Domain `tool.command` allows a configurable executable name/path for external tools. -- Extensibility for downstream ESLint behavior is via ESLint Flat Config composition from the shipped preset (`@matrixai/lint/configs/eslint.js`) and CLI config selection flags such as `--eslint-config` and `--user-config`. - -### Backward compatibility (v1) - -Existing v1 config: - -```json -{ - "tsconfigPaths": ["./tsconfig.json"], - "forceInclude": ["scripts"] -} -``` - -Mapping rule: - -- v1 maps to v2 `domains.eslint.tsconfigPaths` and `domains.eslint.forceInclude`. - -### Target normalization and tsconfig alignment rules - -- If multiple tsconfig paths are configured, file-target derivation must treat them as a union, not only the first entry. -- Include pattern normalization must be extension-aware: - - extensionless include entries may have language extensions expanded - - extension-bearing include entries must be preserved as-is. -- Parser project inputs and wrapper-level file targets must be derived from the same normalized tsconfig set. - ---- - -## Execution semantics - -### Ordering - -Define a stable default domain order for readability and compatibility, while allowing explicit ordering in config: - -1. `eslint` -2. `shellcheck` -3. `markdown-prettier` - -### Exit codes - -Proposed exit codes (subject to validation with downstream CI expectations): - -- `0`: all executed domains succeeded; skipped domains were only skipped for non-fatal reasons. -- `1`: lint/format violations found in at least one executed domain. -- `2`: usage/config error (invalid flags, invalid config file, unknown domain ID). -- `3`: missing required tool or missing optional tool for an explicitly requested domain. -- `4`: unexpected internal error. - -If downstream requires a single non-zero code, document that any non-zero is failure; the specific code is for diagnosis. - -### Warnings vs errors - -- Skipping auto-selected optional-tool domains emits a warning but does not fail. -- Explicitly requested domains missing tools emit an error and fail. -- Provide a final summary that lists executed, skipped, and failed domains. - -### Aggregation invariants - -- The command must never return before final outcome aggregation and summary emission. -- Domain exceptions must be normalized into domain failure records so the summary still prints once. -- Final process exit must be decided exactly once from aggregated domain outcomes and usage/config validation results. - ---- - -## Command behavior matrix - -Assume the project contains `src/**/*.ts`, `docs/**/*.md`, `scripts/foo.sh`, and `nix/shell.nix`. - -| Invocation | Domain selection intent | Expected executed domains | If `shellcheck` missing | -| --- | --- | --- | --- | -| `matrixai-lint` | auto | eslint, markdown-prettier, shellcheck (if relevant) | shellcheck skipped with warning | -| `matrixai-lint --fix` | auto + fix | eslint (fix), markdown-prettier (write), shellcheck (check) | shellcheck skipped with warning | -| `matrixai-lint --domain eslint` | explicit | eslint only | n/a | -| `matrixai-lint --domain shellcheck` | explicit | shellcheck only | fail (missing tool) | -| `matrixai-lint --skip-domain shellcheck` | auto minus one | eslint, markdown-prettier | n/a | -| `matrixai-lint docs` | auto scoped | markdown-prettier (and maybe eslint if JS files under docs) | likely not relevant | -| `matrixai-lint --eslint "src/**/*.ts"` | implicit eslint targeting | eslint (explicit targets) + other auto domains unless skipped | shellcheck still auto (unless targets exclude it) | -| `matrixai-lint --eslnt` | invalid option typo | none | n/a | n/a | - -Notes: - -- The engine should treat positional `targets` as the primary scoping mechanism; relevance discovery is applied within that scope. -- Domain-specific target overrides should be documented as either "scope" or "selection"; this plan recommends treating them as scope overrides that also imply selection of that domain. -- For invalid-option invocations, expected outcome is usage/config error exit (`2`) with corrective guidance. - ---- - -## Migration strategy and phased rollout - -### Backward compatibility principles - -- Keep `matrixai-lint` and `matrixai-lint --fix` working without requiring any new config. -- Keep legacy flags, but: - - add new flags for explicit domain selection (`--domain`, `--skip-domain`) - - deprecate ambiguous flags over time (for example, clarify or replace `--shell`). - -### Suggested rollout phases - -1. **Phase 1: Internal refactor (no CLI changes)** - - Introduce the domain abstraction internally and re-implement current behavior using built-in domains. - - Preserve existing fixed sequencing as the default order. - - Remove correctness hazards while preserving user-facing defaults: - - enforce single final aggregation path (no early success return masking failures) - - normalize thrown domain errors into unified reporting. - -2. **Phase 2: Smart detection and missing-tool policy** *(complete)* - - Implemented relevance vs availability model. - - Applied optional-tool skip semantics by default. - - Aligned multi-tsconfig target derivation with parser project configuration (lint targets and ESLint parser projects now share the canonical tsconfig set). - - Fixed include-pattern normalization so extension-bearing entries remain valid. - -3. **Phase 3: New CLI for domain selection** - - Add `--domain`, `--skip-domain`, `--list-domains`, `--explain`. - - Clarify and normalize `--shell` semantics. - - Introduce `--eslint-config` as a clearer alias for legacy `--config`. - - Introduce strict unknown-option handling (with transitional warning period if needed). - -4. **Phase 4: Config schema v2** - - Add `version: 2` schema support. - - Continue supporting v1 config as a subset mapping to the eslint domain. - -5. **Phase 5: Extension point hardening** - - Stabilize built-in domain extension surfaces and document downstream ESLint composition guidance. - - Expand CI matrix/scenarios to cover domain-only invocations not exercised by current repo scripts. - -### Risks and mitigations - -- **Behavior drift in defaults**: mitigate by snapshotting current behavior in tests and shipping `--explain` output for diagnosis. -- **Performance regressions from file discovery**: mitigate by scoping discovery to targets and using globbing with ignores. -- **Windows portability**: mitigate by removing reliance on external `find` and using Node-based traversal. -- **Downstream CI expectations**: mitigate by keeping exit code 1 for "lint violations" and documenting any new non-zero codes. -- **Unknown-option strictness adoption risk**: mitigate with one transitional release of warning-first behavior and explicit migration notes. -- **Hidden correctness regressions** from prior masked-failure paths: mitigate with regression tests that assert failure propagation when later domains are skipped. diff --git a/plans/refactor/STATE.md b/plans/refactor/STATE.md deleted file mode 100644 index f6f31bc..0000000 --- a/plans/refactor/STATE.md +++ /dev/null @@ -1,190 +0,0 @@ -# Refactor epic state: smart detection + domain architecture - -## Status - -- First implementation slice for CLI execution semantics has been delivered. -- The target architecture is described in [`PLAN.md`](PLAN.md). -- Multi-tsconfig targeting alignment is complete; lint target derivation and ESLint parser projects now share the same canonical tsconfig set. - -## Implemented in full multi-tsconfig targeting alignment slice - -- Completed canonical tsconfig normalization in [`src/config.ts`](../../src/config.ts): - - all configured `domains.eslint.tsconfigPaths` are resolved to absolute paths - - unreadable or missing tsconfig files are filtered out - - resulting tsconfig list is deduplicated and deterministically sorted - - fallback to root `tsconfig.json` remains when available and readable -- Completed union-based ESLint target derivation in [`src/utils.ts`](../../src/utils.ts): - - target files are now derived from the union of all configured tsconfig includes - - excludes are merged with cross-tsconfig overlap handling - - `forceInclude` is merged on top and can suppress matching ignore entries - - file and ignore output is deduplicated and deterministically sorted -- Completed include normalization correctness in [`src/utils.ts`](../../src/utils.ts): - - include entries that already carry an extension/glob extension are preserved as-is - - only extensionless include entries are expanded with supported ESLint extensions - - malformed glob synthesis paths from blanket suffixing are eliminated -- Completed parser-project/target alignment across ESLint runtime paths: - - [`src/configs/eslint.ts`](../../src/configs/eslint.ts) continues to source parser project from resolved tsconfig list - - [`src/utils.ts`](../../src/utils.ts) now injects parser `project` override from the same resolved config used for target derivation - - [`src/domains/eslint.ts`](../../src/domains/eslint.ts) detection now derives default scope from the same multi-tsconfig union logic -- Added regression coverage for multi-tsconfig alignment: - - config normalization and missing/unreadable filtering in [`tests/config.test.ts`](../../tests/config.test.ts) - - multi-tsconfig detection and include/exclude/forceInclude behaviors in [`tests/domains/index.test.ts`](../../tests/domains/index.test.ts) - - user-visible stability with missing configured tsconfig path in [`tests/bin/lint.test.ts`](../../tests/bin/lint.test.ts) - -## Implemented in config-schema cleanup + API-boundary slice - -- Completed lint runtime config loading/normalization using a single explicit schema: - - added [`src/config.ts`](../../src/config.ts) - - supports `matrixai-lint-config.json` with explicit `"version": 2` - - normalized output provides a single resolved shape for CLI/engine consumers -- Updated runtime consumers to use the dedicated config module: - - [`src/utils.ts`](../../src/utils.ts) - - [`src/configs/eslint.ts`](../../src/configs/eslint.ts) -- Expanded public exports for coherent extensibility: - - [`package.json`](../../package.json) includes `./configs/*.js` typed/import exports - - canonical downstream preset import is `@matrixai/lint/configs/eslint.js` - - reusable downstream config import path available for `@matrixai/lint/configs/prettier.config.js` -- Updated tests and docs for the new boundary: - - adjusted programmatic export test in [`tests/index.test.ts`](../../tests/index.test.ts) - - added config loader tests in [`tests/config.test.ts`](../../tests/config.test.ts) - - updated user docs in [`README.md`](../../README.md) for schema + `configs/*` imports - -## Implemented in this slice - -- Finalized canonical long-term CLI surface: - - `--domain ` and `--skip-domain ` for explicit inclusion/exclusion - - `--list-domains` prints available domains with descriptions and exits without lint execution - - `--explain` prints per-domain decision details (selection source, relevance, availability, planned action) - - `--eslint-config ` as the canonical explicit ESLint config override - - domain ids remain: `eslint`, `shell`, `markdown` -- Integrated explain/list output with the domain engine (no duplicate decision logic in CLI): - - added decision evaluation and domain-list helpers in [`src/domains/engine.ts`](../../src/domains/engine.ts) - - CLI now consumes those helpers in [`src/bin/lint.ts`](../../src/bin/lint.ts) -- Clarified shell target semantics in CLI help and docs: - - `--shell` now documented as targets (files, roots, or globs), not only globs - - effective behavior remains root-derivation + recursive `*.sh` discovery -- Removed legacy flag surface from docs/CLI path: - - canonical path uses `--domain`, `--skip-domain`, `--eslint-config` - - no backward-compat requirement maintained for `--only`, `--skip`, `--config` in this slice -- Preserved script-level workflow compatibility by updating package scripts to canonical flags: - - `npm run lint` and `npm run lintfix` remain functional workflows and now invoke canonical domain flags -- Added/updated tests for canonical behavior: - - domain selection + explain/list integration in [`tests/domains/index.test.ts`](../../tests/domains/index.test.ts) - - CLI canonical flags, explain output path, list-domains early exit, and script-shape coverage in [`tests/bin/lint.test.ts`](../../tests/bin/lint.test.ts) - -## Implemented in smart-detection completion slice - -- Completed two-axis smart detection across all current built-in domains (`eslint`, `shell`, `markdown`): - - Axis A (project relevance): each domain now performs detection against effective scope roots before execution. - - Axis B (tool availability): each domain reports runtime tool availability independently from relevance. -- Extended the domain engine contract in [`src/domains/engine.ts`](../../src/domains/engine.ts): - - added per-domain `detect` hook returning relevance + availability metadata - - retained ordered orchestration via the domain engine - - enforced single aggregate failure decision from all domain outcomes -- Added shared discovery helpers in [`src/domains/files.ts`](../../src/domains/files.ts): - - pattern-to-root resolution for path/glob inputs - - filesystem extension-based discovery for relevance checks - - relative path normalization for stable CLI invocation -- Updated built-in domains to use detection consistently: - - [`src/domains/eslint.ts`](../../src/domains/eslint.ts): detects JS/TS relevance in effective scope; availability is required - - [`src/domains/shell.ts`](../../src/domains/shell.ts): detects `*.sh` relevance and `shellcheck` availability (optional in auto mode) - - [`src/domains/markdown.ts`](../../src/domains/markdown.ts): detects Markdown/MDX relevance in current default markdown scope; availability is required -- Enforced explicit-vs-auto semantics in engine/orchestration: - - explicit requests are tracked via `--only` and domain target flags (`--eslint`, `--shell`) - - auto + not relevant => skip - - auto + relevant + missing optional tool => warn/skip (non-fatal) - - explicit + missing required tool OR missing optional-now-required tool => deterministic failure - - explicit + no matched files => non-fatal no-op with explicit warning -- Kept backward-compatible flag behavior in selection logic: - - `--eslint` / `--shell` still imply explicit domain selection when used without domain selectors - - `--only` / `--skip` remain stable -- Expanded and reorganized tests: - - CLI orchestration behavior remains in [`tests/bin/lint.test.ts`](../../tests/bin/lint.test.ts) - - moved engine and selection semantics tests to [`tests/domains/index.test.ts`](../../tests/domains/index.test.ts) - -## Implemented in follow-up cleanup slice - -- Removed shell-domain dependence on external `find`: - - shell discovery now walks filesystem roots in Node and collects `*.sh` files before invoking `shellcheck` - - non-existent shell roots are still ignored - - explicit shell requests (`--shell ...` or `--only shell`) still fail if `shellcheck` is missing - - default shell auto-run still warns/skips when `shellcheck` is missing -- Removed runtime dependency-injection indirection from CLI entry: - - removed `MainDeps`, `defaultMainDeps`, and `mainWithDeps` from `src/bin/lint.ts` - - retained `main` as the runtime/default export entrypoint -- Refactored CLI tests to use Jest spies/mocks instead of `mainWithDeps`: - - tests now mock dependency behavior through module spies (for example `utils.commandExists`) - - shell assertions updated to verify direct `shellcheck` invocation behavior - -## Implemented in domain-engine core + packaging alignment slice - -- Introduced an internal domain engine core: - - added [`src/domains/engine.ts`](../../src/domains/engine.ts) containing a domain plugin contract, registry creation, and ordered execution with aggregated failure status - - added built-in domain plugin modules and registry composition under [`src/domains/`](../../src/domains/) - - added duplicate-domain registration protection in the registry - - preserved deterministic ordered execution using the existing built-in order (`eslint`, `shell`, `markdown`) -- Refactored CLI orchestration to run through the domain engine: - - [`src/bin/lint.ts`](../../src/bin/lint.ts) now builds a built-in domain registry and executes selected domains through the engine - - preserved external behavior and compatibility: - - existing flags (`--fix`, `--user-config`, `--config`, `--eslint`, `--shell`, `--only`, `--skip`) - - inferred selection from `--eslint` and `--shell` - - shell explicit-vs-auto missing-tool behavior - - single aggregate final pass/fail result -- Added/updated tests for engine and API surface parity: - - [`tests/bin/lint.test.ts`](../../tests/bin/lint.test.ts) now includes direct engine tests (ordered execution, failure aggregation, duplicate registration guard) - - [`tests/index.test.ts`](../../tests/index.test.ts) now validates package programmatic exports (`#index.js` named `config` and `#config.js` default config) -- Standardized programmatic package surface: - - added [`src/index.ts`](../../src/index.ts) as the public barrel exporting named `config` and public types - - added [`src/config.ts`](../../src/config.ts) as the default-export config subpath module - - updated [`package.json`](../../package.json) exports map: - - includes `./package.json` - - keeps `.` with `types` + `import` - - keeps `./*.js` with `types` + `import` - - keeps `./*` fallback to `dist/*` - - removed custom `./config` export block - - preserved `imports` compatibility mapping `#* -> ./dist/*` - -## Prettier config file-format decision (question follow-up) - -- Decision: keep the Prettier config as JavaScript runtime source, and rename from `.mjs` to `.js` (ESM due to package `type: module`) rather than converting to TypeScript. -- Implemented changes: - - replaced [`src/configs/prettier.config.mjs`](../../src/configs/prettier.config.mjs) with [`src/configs/prettier.config.js`](../../src/configs/prettier.config.js) - - updated imports and runtime references in: - - [`src/configs/eslint.ts`](../../src/configs/eslint.ts) - - [`src/bin/lint.ts`](../../src/bin/lint.ts) -- Rationale: - - the file is consumed directly at runtime by both ESLint config composition and Prettier CLI `--config` - - keeping runtime config as JS avoids introducing extra TS-to-runtime coupling for a non-domain logic config asset - - `.js` aligns with repo ESM boundary (`type: module`) and is simpler than `.mjs` while staying explicit and portable - - this keeps build/package behavior robust without additional post-build copy or loader complexity - -## Current pain points (observed in current implementation) - -- Domains run in a fixed sequence and cannot be cleanly targeted. -- Domain targeting flags are inconsistent (for example, shell targeting is described like globs but treated like search roots). -- Default scope is tightly coupled to `cwd` and `tsconfig` assumptions. -- Optional external tools are not modeled cleanly (missing tools are sometimes warnings, sometimes implicit no-ops). -- Extensibility is constrained (no per-domain plugin/config abstraction). - -Notes on resolved items: - -- Domain execution is now backed by an internal plugin registry/engine abstraction. - -## Decisions (draft) - -- Introduce a first-class domain/plugin architecture. -- Split auto-discovery into two axes: project relevance vs tool availability. -- Classify dependencies as required vs optional, with an explicit-request escalation rule. -- Introduce a new CLI model that supports domain inclusion/exclusion and consistent target semantics. - -## Open questions - -- Final naming for the new flags (for example `--domain` vs `--only`, `--skip` vs `--exclude-domain`). -- Config schema evolution strategy: extend `matrixai-lint-config.json` in place vs introduce a v2 file name. - -## Next actions - -- Final cleanup for release: - - polish docs for domain/target selection and public import paths - - align scripts to canonical domain-targeting CLI usage - - cut release (version bump, build, test, lintfix) diff --git a/plans/refactor/questions.md b/plans/refactor/questions.md deleted file mode 100644 index a5cf455..0000000 --- a/plans/refactor/questions.md +++ /dev/null @@ -1,3 +0,0 @@ -I noticed that shellcheck run also depend on `find`. I wonder if that's a good idea, since that means `find` also must exist in the environment to run it... what do you think we should do about that? - -I also think the lint.ts code @/src/bin/lint.ts is werid with `mainWithDeps`, I don't quite like it. Can you rewrite that script so that only `main` exists, and then explain if in the tests you actually need it? Like can you not make use of jest mocking to do any necessary injection?