-
Notifications
You must be signed in to change notification settings - Fork 50
Comparing changes
Open a pull request
base repository: fallow-rs/fallow
base: v2.64.0
head repository: fallow-rs/fallow
compare: v2.65.0
- 15 commits
- 84 files changed
- 5 contributors
Commits on May 4, 2026
-
Configuration menu - View commit details
-
Copy full SHA for dfb8a5f - Browse repository at this point
Copy the full SHA dfb8a5fView commit details -
Configuration menu - View commit details
-
Copy full SHA for 564afbe - Browse repository at this point
Copy the full SHA 564afbeView commit details
Commits on May 5, 2026
-
test(extract): cover Vue
generic="T extends X<Y>"parsingLock in fallow's regex-based attrs scan so a Vue script-setup generic constraint with a type argument keeps the script body intact and oxc parses it normally. Asserts that both the value import and the type-only import survive the SFC boundary with correct `is_type_only` flags.
Configuration menu - View commit details
-
Copy full SHA for 0d426c6 - Browse repository at this point
Copy the full SHA 0d426c6View commit details -
test(extract,core): cover Svelte type-only imports across the SFC bou…
…ndary Lock in fallow's contract that type-only imports inside Svelte `<script lang="ts">` blocks survive extraction with `is_type_only=true` and are tracked as type-referenced when consumed only as type annotations. Coverage at both the extraction layer (unit test) and the analysis layer (svelte-project fixture extension), so an upstream `export type` whose only consumer is a type annotation stays reachable.
Configuration menu - View commit details
-
Copy full SHA for f1c1caf - Browse repository at this point
Copy the full SHA f1c1cafView commit details -
fix(extract): scan Vue
generic/ Sveltegenericsattributes for t……ype references A type-only import whose only consumer is the script-tag `generic="T extends Test<boolean>"` (Vue) or `generics="T extends Item"` (Svelte) was falsely flagged as `unused_types` because the constraint lives on the tag, not in the script body. The body parse had no symbol references for the import, oxc_semantic classified the binding as unused, and the upstream `export type` got dead-code reported. Fix: when a script tag carries a generic / generics attribute, build an augmented source that appends a synthetic local type alias consuming the constraint, and run the binding-usage analyser on that augmented parse. The extractor still walks the original body, so synthetic declarations don't leak into module info. The non-generic code path is untouched.
Configuration menu - View commit details
-
Copy full SHA for bf6349a - Browse repository at this point
Copy the full SHA bf6349aView commit details -
docs(rules): note generic/generics attribute scanning in extract-crat…
…e.md The extract-crate rule file lists each module's capabilities as system context for future Claude sessions. Adding a brief mention of the new generic/generics attribute scanning keeps the rule file accurate.
Configuration menu - View commit details
-
Copy full SHA for 36929fe - Browse repository at this point
Copy the full SHA 36929feView commit details -
chore(deps): bump crate-ci/typos from 1.45.1 to 1.45.2 (#277)
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.45.1 to 1.45.2. - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](crate-ci/typos@cf5f1c2...7c57295) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.45.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Configuration menu - View commit details
-
Copy full SHA for b92dda2 - Browse repository at this point
Copy the full SHA b92dda2View commit details -
chore(deps-dev): bump @tanstack/intent in /npm/fallow (#278)
Bumps [@tanstack/intent](https://github.com/TanStack/intent) from 0.0.32 to 0.0.36. - [Release notes](https://github.com/TanStack/intent/releases) - [Commits](https://github.com/TanStack/intent/commits/v0.0.36) --- updated-dependencies: - dependency-name: "@tanstack/intent" dependency-version: 0.0.36 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Configuration menu - View commit details
-
Copy full SHA for 8d0d31d - Browse repository at this point
Copy the full SHA 8d0d31dView commit details -
feat: detect Lit / Web Components registered classes (knip #1394)
* feat(types): add is_side_effect_used flag to ExportInfo Threads a boolean through ExportInfo, scaffolding for marking exports that are alive only via runtime registration (Lit @CustomElement decorators, customElements.define calls). Defaults to false everywhere; no behavioral change yet. * feat(graph): plumb is_side_effect_used to ExportSymbol + analyzer Threads the flag from ExportInfo through ModuleGraph::build_module_node into ExportSymbol, then OR-checks it alongside !references.is_empty() in find_unused_exports. Reachable modules whose exports are flagged as side-effect-used are no longer flagged as unused-export. * feat(extract): detect Lit @CustomElement and customElements.define Adds two new helpers in visitor/helpers.rs and wires them into the AST walk: - has_lit_class_decorator(class): matches @CustomElement('tag') class decorators (bare-import and member-call forms). - extract_custom_elements_define(call): matches customElements.define( STRING, IDENT) call expressions. Both pattern matches push the class identifier into a new ModuleInfoExtractor.side_effect_registered_class_names set. A post-walk finalizer flips ExportInfo.is_side_effect_used = true for any export whose local binding name is in the set, so unused-export detection no longer reports Web Component classes as dead. Persisted across cache rounds via a new CachedExport.is_side_effect_used field; CACHE_VERSION bumps 65 -> 66. * feat(core): Lit framework plugin + side-effect class member detection - New crates/core/src/plugins/lit.rs with three heritage-scoped used_class_member rules (LitElement, ReactiveElement, HTMLElement) so Lit lifecycle and native Custom Elements lifecycle members are not reported as unused on framework-managed classes. - New Plugin trait method used_class_member_rules() for emitting ScopedUsedClassMemberRule entries; default empty Vec, only the new Lit plugin overrides it for now. - crates/core/src/analyze/unused_members.rs ORs is_side_effect_used alongside !references.is_empty() in the skip-whole-export-dead guard so member analysis still runs on @CustomElement / customElements.define registered classes. - Integration fixture tests/fixtures/lit-custom-element/ exercises the decorator form, the customElements.define form, the order-independent separate-then-define form, and the @decorators.customElement member-call decorator form. Two integration tests assert exports are credited and that lifecycle members (render, connectedCallback, observedAttributes) are allowlisted while genuinely unused helpers are still reported. * style: rustfmt drift on lit plugin and builtin registry * fix(extract): credit anonymous default-class @CustomElement rust-reviewer caught that 'export default @CustomElement("x") class extends LitElement {}' (no class id) slipped through the side-effect flag plumbing. The class has no identifier to key by name, and the Default export's local_name is unset, so the post-walk finalizer can not match. Fix: in visit_class, when @CustomElement is detected and class.id is None, flip is_side_effect_used directly on the most recent Default export (which was just pushed by visit_export_default_declaration before walk recursed into the class). Adds anonymous-default.ts fixture and an integration assertion to lock the behavior. * docs: lit / custom-element entry in detection.md + README Adds a new Analysis-level entry to .claude/rules/detection.md describing the Lit / Web Components registration credit (knip #1394) and lists Lit under the Frameworks plugin table in README.md. Documentation-only; no behavior change. * fix(extract): gate @CustomElement credit on Lit decorator import The previous implementation flipped is_side_effect_used whenever a class had a decorator whose callee was named 'customElement', regardless of where the binding came from. A user-defined function called 'customElement' would silently suppress unused-export reporting on every class it decorated. Changes: - visitor/helpers.rs: lit_custom_element_decorator() now returns the local binding name(s) used at the decorator call site, in both bare identifier and namespace-member-call shapes. No import validation happens at the visitor's class node; that's deferred until after the full walk completes. - visitor/mod.rs: a new lit_custom_element_candidates Vec collects every @customElement-shaped decorator alongside its target (named class or anonymous-default export slot). After the walk, apply_lit_custom_element_ candidates() resolves each candidate against the imports list, gating credit on a binding that came from lit/decorators.js or lit/decorators/custom-element.js. Named-import aliases (`import { customElement as ce }`) match because the validator compares the ImportInfo.local_name to the decorator's local name and the ImportedName::Named to the canonical 'customElement' string. - visitor/visit_impl.rs: visit_class records candidates instead of flipping the flag in place; anonymous-default exports record the export-vec index so post-walk validation flips the right slot. - analyze/unused_members.rs: native HTMLElement lifecycle members (connectedCallback, disconnectedCallback, observedAttributes, etc.) are now built-in heritage-scoped allowlists in the member analyzer. Plain Web Components projects with no Lit dependency still get correct lifecycle handling. - plugins/lit.rs: drops the HTMLElement-scoped rule (now covered by the built-in) and keeps the LitElement / ReactiveElement rules for Lit- specific lifecycle members (render, firstUpdated, etc.). - cache/types.rs: CACHE_VERSION bumps 66 -> 67. - New fixture tests/fixtures/web-components-native/ exercises (a) plain customElements.define with no Lit at all (positive: lifecycle allowlisted) and (b) a non-Lit decorator named 'customElement' (negative: the class export must still be reported as unused). - New fixture tests/fixtures/lit-custom-element/src/named-import-alias- decorator.ts covers `import { customElement as ce }`. - Two new integration tests in web_components.rs and one extra assertion in lit_custom_element.rs lock the import-aware contract. - detection.md note updated to match the new contract.
Configuration menu - View commit details
-
Copy full SHA for 471d0f5 - Browse repository at this point
Copy the full SHA 471d0f5View commit details -
feat(npm): ship schema.json inside the fallow package
* feat(npm): ship schema.json inside the fallow package (#275) Today the published `fallow` npm package omits `schema.json`, so the only stable way to point `$schema` at a matching schema is the `raw.githubusercontent.com/.../main/schema.json` URL — which: - drifts from the installed CLI version (URL tracks main, install is pinned to a tag), - requires network on every fresh editor open and trips up corporate proxies that block raw.githubusercontent.com, - has no clean offline / airgapped story. Two-line fix: - Add `schema.json` to `npm/fallow/package.json`'s files array. - In the release workflow, copy `schema.json` from the repo root to `npm/fallow/schema.json` immediately before the `npm publish ./npm/fallow` step. We can't rely on a prepublishOnly hook here because the existing publish call uses `--ignore-scripts`. After this, consumers can write: { "$schema": "./node_modules/fallow/schema.json", ... } …and get version-aligned validation with zero network calls. The remote URL keeps working as a fallback for users without a local install. The optional `fallow init` template change suggested in the issue isn't included here — that lives in the Rust CLI and is best done as a follow-up once this artifact is actually published. * ci(npm): assert schema package artifact --------- Co-authored-by: Chris (ChrisJr404) <11917633+ChrisJr404@users.noreply.github.com> Co-authored-by: Bart Waardenburg <bart@waardenburg.dev>
Configuration menu - View commit details
-
Copy full SHA for 547ac02 - Browse repository at this point
Copy the full SHA 547ac02View commit details -
fix(migrate): accept trailing commas in jsonc input (#280)
* fix(migrate): accept trailing commas in jsonc input Closes #276. real-world JSONC files (knip.jsonc, tsconfig.json, .vscode/settings.json, etc.) routinely use trailing commas. `load_json_or_jsonc` ran the input through `json_comments::StripComments` and then handed the result to serde_json, which rejects trailing commas with "trailing comma at line N column M". Add a final pass that drops `,` immediately before `}` or `]` while leaving commas inside string literals untouched. The pass runs only when the comment-stripped parse fails, so already-valid input has zero overhead. The new `strip_trailing_commas` helper is a small byte-level state machine (no extra deps) that tracks in-string + escaped state, so strings like "hello, world," survive verbatim. * fix(migrate): harden jsonc trailing comma cleanup --------- Co-authored-by: ChrisJr404 <chris@hacknow.com> Co-authored-by: Bart Waardenburg <bart@waardenburg.dev>
Configuration menu - View commit details
-
Copy full SHA for 47306d3 - Browse repository at this point
Copy the full SHA 47306d3View commit details -
fix(unused-class-members): trace Angular signal queries and plural Qu…
…eryList iteration (#283) * fix(extract): trace Angular signal queries and plural QueryList iteration The `unused-class-members` analyzer already credited methods called through `@ViewChild` / `@ContentChild` decorator queries because the property's TS type annotation was wired into the bound-member-access pipeline. Six other first-class Angular query patterns were missed: - `viewChild<T>(...)`, `contentChild<T>(...)` — singular signal factories whose initializer return type is `Signal<T>`. The property has no explicit type annotation, and the call site `this.vc()?.method()` puts a `CallExpression` between `this.vc` and `method`, which the static-member resolver did not descend into. - `viewChildren<T>(...)`, `contentChildren<T>(...)` — plural signal factories iterated as `this.vcs().forEach(c => c.method())`. Even with a known element type, the arrow's `c` parameter had no resolved type. - `@ViewChildren` / `@ContentChildren` — plural decorator queries typed `QueryList<T> | undefined`. `extract_type_annotation_name` flattens the annotation to the bare `"QueryList"` identifier, so the element type was never reachable. Approach (smallest change that closes the gap): 1. Add `extract_angular_signal_query` to recognize the four signal-query factories and pull out `T` from either the explicit type argument or the first identifier argument (the locator-class form). 2. Add `extract_query_list_element_type` to peel `QueryList<T>` (and the nullable `QueryList<T> | null|undefined` variants) out of a TS type annotation, and `has_angular_plural_query_decorator` to recognize the `@ViewChildren` / `@ContentChildren` decorator forms. 3. In `visit_property_definition`, register the discovered element type on `ModuleInfoExtractor`: - Singular signal queries → `binding_target_names["this.<name>()"] = T` - Plural signal queries → `iterable_element_types["this.<name>()"] = T` - Plural decorator queries → `iterable_element_types["this.<name>"] = T` 4. Extend `static_member_object_name` to descend into a zero-argument `CallExpression` (yielding `"this.vc()"`) and into a `ChainExpression` so `this.vc()?.method` and `this.dvcs?.forEach(...)` resolve through the existing pipeline. 5. In `visit_call_expression`, when the callee is `<receiver>.forEach` (or the optional-chained form) and `<receiver>` is a registered iterable, bind the arrow callback's first parameter to the element type. The flat `binding_target_names` map then drives `c.method()` resolution at end-of-visit, matching the existing scope-unaware convention noted in the visitor module. Adds the issue's full eight-pattern Angular reproducer as a single test asserting that all eight `ChildComponent` methods are traced through `MemberAccess { object: "ChildComponent", member: <name> }`. Closes #274 * fix(extract): address Angular query review findings --------- Co-authored-by: ChrisJr404 <chris@hacknow.com> Co-authored-by: Bart Waardenburg <bart@waardenburg.dev>
Configuration menu - View commit details
-
Copy full SHA for 2ea51fc - Browse repository at this point
Copy the full SHA 2ea51fcView commit details -
Configuration menu - View commit details
-
Copy full SHA for 6e27b02 - Browse repository at this point
Copy the full SHA 6e27b02View commit details -
fix(plugins): treat vite config default export as framework-used (#285)
Fixes #282. Mirrors the vitest fix in #271. With --include-entry-exports, fallow flagged vite.config.* default exports as unused even though Vite's CLI consumes that default export. The vite plugin now contributes used_exports for vite.config.{ts,js,mts,mjs} (default), matching the shape already used for vitest.config.* and vitest.workspace.*. Adds a regression fixture (vite-include-entry-exports-workspace) and an integration test that pins the new behavior. Existing entry-export validation tests continue to ensure --include-entry-exports still flags truly-unused named exports on non-config entries. Co-authored-by: Chris (ChrisJr404) <chris@hacknow.com>
Configuration menu - View commit details
-
Copy full SHA for 868d44d - Browse repository at this point
Copy the full SHA 868d44dView commit details -
Configuration menu - View commit details
-
Copy full SHA for 2b1b696 - Browse repository at this point
Copy the full SHA 2b1b696View commit details
This comparison is taking too long to generate.
Unfortunately it looks like we can’t render this comparison for you right now. It might be too big, or there might be something weird with your repository.
You can try running this command locally to see the comparison on your machine:
git diff v2.64.0...v2.65.0