Skip to content

fix(vue-directives): avoid stale lastIndex on the global directive regex - #579

Open
NgoQuocViet2001 wants to merge 1 commit into
unjs:mainfrom
NgoQuocViet2001:fix-directive-regex-lastindex
Open

NgoQuocViet2001 wants to merge 1 commit into
unjs:mainfrom
NgoQuocViet2001:fix-directive-regex-lastindex

Conversation

@NgoQuocViet2001

@NgoQuocViet2001 NgoQuocViet2001 commented Oct 24, 2026 •

Copy link
Copy Markdown

resolves #578

RE_DIRECTIVE has the g flag, and the check for leftover directives calls RE_DIRECTIVE.test(), which leaves lastIndex set after a match. matchAll copies that lastIndex, so the next transform starts scanning partway into the file. With <div v-awesome-directive v-missing></div>, the first injectImports call adds import _directive_awesome_directive from ..., but a second call on the same code returns it unchanged, still calling _resolveDirective("awesome-directive"). A different file transformed next can also lose the resolveDirective import while keeping a _resolveDirective(...) call, which throws at render.

The check now uses String#search, which does not touch lastIndex. Going back to .match() is not an option because e18e/prefer-regex-test autofixes it to .test(), which is how this changed in 62a9ede. The "single named directive" and "single mixed directives" snapshots were regenerated with the broken output in 429d84a, so they are restored, and a new test transforms the same code twice and expects the same result.

Ran:

  • pnpm exec vitest run test/vue-directives.test.ts: 3 failed without the fix (the two restored snapshots and the new test), 14 passed with it
  • pnpm exec vitest run: 28 files, 255 tests passed
  • pnpm run typecheck, pnpm run lint, pnpm run build: no errors

Checked:

  • The repro from the issue against published unimport 7.0.2 shows the same behavior

Summary by CodeRabbit

  • Bug Fixes
    • Vue templates with registered directives now use direct imports instead of generated runtime resolution calls. Unregistered directives continue to use runtime resolution.
    • Repeated import injection now produces consistent output.

@coderabbitai

coderabbitai Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 34fd048f-ee16-4985-ba45-38b15e2f8a40
Commits

Reviewing files that changed from the base of the PR and between bbd0776 and 29ca7ec.

Files selected for processing: 2
  • src/addons/vue-directives.ts
  • test/vue-directives.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 3 remain after this review.

Walkthrough

The Vue directive addon now checks for remaining directives without changing the global regex’s lastIndex. Tests cover registered and unresolved directives, expected import output, and repeated import injection.

Changes: Vue directive import stability

Layer / File(s) Summary
Directive check and transform coverage
src/addons/vue-directives.ts, test/vue-directives.test.ts
The addon uses search to check for remaining directive references. Tests verify direct imports for registered directives, runtime resolution for unresolved directives, and identical output across repeated import injections.

Priority: Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: antfu

Merge Risk: Minimal · up to 29ca7

The reported directive-transform instability is addressed, with no merge-blocking risk established.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: preventing stale lastIndex values on the global directive regex.
Linked Issues check Passed The change satisfies issue #578. src/addons/vue-directives.ts uses s.toString().search(RE_DIRECTIVE), so the global regex lastIndex is not changed before the next scan. The restored snapshots sh…
Out of Scope Changes check Passed The changes stay within issue #578. The source change fixes the Vue directive leftover check. The snapshot updates and repeated-transform test verify the requested behavior. No unrelated source, API, …
Full details: Linked Issues check

Explanation

The change satisfies issue #578. src/addons/vue-directives.ts uses s.toString().search(RE_DIRECTIVE), so the global regex lastIndex is not changed before the next scan. The restored snapshots show known directives imported directly without _resolveDirective calls. The new repeated-transform test verifies identical output on both calls when a known directive and v-missing are present. The test preserves runtime resolution for the unresolved directive.

Full details: Out of Scope Changes check

Explanation

The changes stay within issue #578. The source change fixes the Vue directive leftover check. The snapshot updates and repeated-transform test verify the requested behavior. No unrelated source, API, or feature changes appear in the whole-pull-request diff.

Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Warning

Some tools did not complete. Review the errors below.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/addons/vue-directives.ts

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.

test/vue-directives.test.ts

ESLint skipped: the matched ESLint configuration already failed (missing-dependency).

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

vueDirectives: directive imports are skipped after an earlier transform leaves a directive unresolved

1 participant