feat(search-box): Exception events can be thrown during validation.#50
feat(search-box): Exception events can be thrown during validation.#50discreted66 wants to merge 1 commit intoopentiny:mainfrom
Conversation
WalkthroughA new validation feature is added to the search-box component that validates input tags against regular expressions. Two demo components showcase this functionality with error handling. The core validation logic is implemented in composables with a validate-error event. The package version is bumped to stable release. Changes
Sequence DiagramsequenceDiagram
participant User
participant SearchBox
participant Dropdown
participant Validation
participant Component
User->>SearchBox: Input tag value
SearchBox->>Dropdown: Create tag
Dropdown->>Validation: Validate tag against regexp
alt Valid Tag
Validation->>Dropdown: Return valid
Dropdown->>SearchBox: Apply tag to model
SearchBox->>Component: Update v-model
else Invalid Tag
Validation->>Dropdown: Return invalid with details
Dropdown->>Component: Emit validate-error event
Component->>Component: Build error message
Component->>User: Display error block
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@packages/docs/search-box/validate-error.vue`:
- Line 19: The import of Message is unused in this component; remove the unused
symbol by deleting Message from the import statement (the import line that
currently reads import { Message } from "@opentiny/vue") in validate-error.vue
so the component no longer imports an unreferenced symbol.
In `@packages/search-box/src/composables/use-dropdown.ts`:
- Around line 222-229: When all tags fail regex validation the code currently
emits the validate-error with invalidTags but doesn't clear the input because
updateModelValue/newTagUpdateModelValue aren't called; after emitting the error
in the block that checks invalidTags.length > 0 (where emit('validate-error', {
invalidValues: invalidTags, field: prevItem.field, label: prevItem.label,
regexp: regexp.toString() }) is called), invoke resetInput(state) so the input
is cleared when no tag updates occur (ensure this happens only in the path where
tagList validation produced only invalidTags and no
updateModelValue/newTagUpdateModelValue calls were made).
- Around line 210-229: The regexp used in the per-tag validation (variable
regexp) is stateful when it has the g or y flags; reset regexp.lastIndex = 0
before each call to regexp.test() in the tagged path (the loop that iterates
tagList and calls newTagUpdateModelValue(prevItem, propItem, tag)) and also
before any other uses (e.g., the unlabeled path where
regexp.test(state.inputValue) is used during items.find); alternatively
construct a fresh RegExp instance for each test (new RegExp(regexp)) to avoid
shared lastIndex, ensuring the emit('validate-error', {...}) behavior remains
unchanged.
🧹 Nitpick comments (2)
packages/search-box/src/composables/use-dropdown.ts (1)
261-286: Duplicated validation logic — consider extracting a helper.The validation block here (lines 263–281) is nearly identical to lines 212–229. The only differences are the update function called and the item reference. A shared helper would reduce duplication and ensure both paths stay in sync.
♻️ Sketch of a shared helper
+ const validateAndUpdate = ( + tagList: string[], + regexp: RegExp | undefined, + item: any, + updateFn: (tag: string) => void + ) => { + if (regexp) { + const invalidTags: string[] = [] + for (const tag of tagList) { + regexp.lastIndex = 0 + if (regexp.test(tag)) { + updateFn(tag) + } else { + invalidTags.push(tag) + } + } + if (invalidTags.length > 0) { + emit('validate-error', { + invalidValues: invalidTags, + field: item.field, + label: item.label, + regexp: regexp.toString() + }) + } + } else { + for (const tag of tagList) { + updateFn(tag) + } + } + }Then use it in both paths:
// Labeled path validateAndUpdate(tagList, regexp, prevItem, (tag) => newTagUpdateModelValue(prevItem, propItem, tag)) // Unlabeled path validateAndUpdate(tagList, regexp, currentItem, (tag) => updateModelValue(currentItem, {}, label, tag))packages/docs/search-box/validate-error.vue (1)
57-64: Error message is never cleared after successful input.Once
errorMessageis set, it persists indefinitely — even after the user successfully adds valid tags. For a demo, consider clearing it (e.g., on@changeor with a timer) so it doesn't mislead users into thinking the error is still active.
|
|
||
| <script setup lang="ts"> | ||
| import { ref, reactive } from "vue"; | ||
| import { Message } from "@opentiny/vue"; |
There was a problem hiding this comment.
Unused import: Message is imported but never used.
Message from @opentiny/vue is imported but not referenced anywhere in this component.
🧹 Remove unused import
-import { ref, reactive } from "vue";
-import { Message } from "@opentiny/vue";
+import { ref, reactive } from "vue";🤖 Prompt for AI Agents
In `@packages/docs/search-box/validate-error.vue` at line 19, The import of
Message is unused in this component; remove the unused symbol by deleting
Message from the import statement (the import line that currently reads import {
Message } from "@opentiny/vue") in validate-error.vue so the component no longer
imports an unreferenced symbol.
| // 如果配置项有 regexp 校验条件,对每个 tag 单独进行校验 | ||
| if (regexp) { | ||
| const invalidTags = [] | ||
| for (const tag of tagList) { | ||
| // 每个 tag 单独用 regexp 校验 | ||
| if (regexp.test(tag)) { | ||
| newTagUpdateModelValue(prevItem, propItem, tag) | ||
| } else { | ||
| invalidTags.push(tag) | ||
| } | ||
| } | ||
| // 当有校验不合法的值时,抛出事件 | ||
| if (invalidTags.length > 0) { | ||
| emit('validate-error', { | ||
| invalidValues: invalidTags, | ||
| field: prevItem.field, | ||
| label: prevItem.label, | ||
| regexp: regexp.toString() | ||
| }) | ||
| } |
There was a problem hiding this comment.
Stateful RegExp.test() bug when regex has g or y flag.
RegExp.prototype.test() is stateful for regexes with the g or y flag — each call advances lastIndex. When iterating tagList with the same regexp, subsequent test() calls may incorrectly fail or pass because lastIndex is not reset between iterations.
This risk is higher in the unlabeled path (lines 263–271), where regexp.test(state.inputValue) is called first during items.find() (line 243), and the same regex object is reused in the per-tag loop — lastIndex carries over.
Consider resetting lastIndex before each test, or using a non-stateful check like regexp.test(tag) with a fresh regex. Since users can supply any regex, the component should be defensive.
🛡️ Proposed fix — reset lastIndex before each test
For the labeled path (lines 210–229):
if (regexp) {
const invalidTags = []
for (const tag of tagList) {
- // 每个 tag 单独用 regexp 校验
- if (regexp.test(tag)) {
+ regexp.lastIndex = 0
+ if (regexp.test(tag)) {
newTagUpdateModelValue(prevItem, propItem, tag)
} else {
invalidTags.push(tag)For the unlabeled path (lines 263–271):
if (regexp) {
const invalidTags = []
for (const tag of tagList) {
- // 每个 tag 单独用 regexp 校验
- if (regexp.test(tag)) {
+ regexp.lastIndex = 0
+ if (regexp.test(tag)) {
updateModelValue(currentItem, {}, label, tag)
} else {
invalidTags.push(tag)🤖 Prompt for AI Agents
In `@packages/search-box/src/composables/use-dropdown.ts` around lines 210 - 229,
The regexp used in the per-tag validation (variable regexp) is stateful when it
has the g or y flags; reset regexp.lastIndex = 0 before each call to
regexp.test() in the tagged path (the loop that iterates tagList and calls
newTagUpdateModelValue(prevItem, propItem, tag)) and also before any other uses
(e.g., the unlabeled path where regexp.test(state.inputValue) is used during
items.find); alternatively construct a fresh RegExp instance for each test (new
RegExp(regexp)) to avoid shared lastIndex, ensuring the emit('validate-error',
{...}) behavior remains unchanged.
| if (invalidTags.length > 0) { | ||
| emit('validate-error', { | ||
| invalidValues: invalidTags, | ||
| field: prevItem.field, | ||
| label: prevItem.label, | ||
| regexp: regexp.toString() | ||
| }) | ||
| } |
There was a problem hiding this comment.
Input not cleared when all tags fail validation.
When every tag in tagList fails regex validation, neither updateModelValue nor newTagUpdateModelValue is called, so resetInput(state) is never triggered. The invalid text remains in the input field after the error event fires. If this is intentional (to let users correct their input), consider documenting it; otherwise, call resetInput(state) after emitting the error.
🤖 Prompt for AI Agents
In `@packages/search-box/src/composables/use-dropdown.ts` around lines 222 - 229,
When all tags fail regex validation the code currently emits the validate-error
with invalidTags but doesn't clear the input because
updateModelValue/newTagUpdateModelValue aren't called; after emitting the error
in the block that checks invalidTags.length > 0 (where emit('validate-error', {
invalidValues: invalidTags, field: prevItem.field, label: prevItem.label,
regexp: regexp.toString() }) is called), invoke resetInput(state) so the input
is cleared when no tag updates occur (ensure this happens only in the path where
tagList validation produced only invalidTags and no
updateModelValue/newTagUpdateModelValue calls were made).
feat:校验支持抛出异常事件,并补充相应示例,优化数字区间无单位情况下展示
Summary by CodeRabbit
New Features
Bug Fixes
Chores