From 57b5e203e80d5f0ef354fa62697292cb62a39b36 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Thu, 3 Sep 2026 19:25:53 +0800 Subject: [PATCH] fix: complete editable input hints --- src/editableInputPlaceholders.test.mjs | 54 +++++++++++++++++++ .../first-leg/views/QuickOrderView.vue | 10 ++-- .../views/WarehouseServiceView.vue | 6 +-- 3 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 src/editableInputPlaceholders.test.mjs diff --git a/src/editableInputPlaceholders.test.mjs b/src/editableInputPlaceholders.test.mjs new file mode 100644 index 0000000..7b9a91a --- /dev/null +++ b/src/editableInputPlaceholders.test.mjs @@ -0,0 +1,54 @@ +import assert from 'node:assert/strict' +import { readdirSync, readFileSync } from 'node:fs' +import path from 'node:path' +import test from 'node:test' +import { fileURLToPath } from 'node:url' + +const sourceRoot = path.dirname(fileURLToPath(import.meta.url)) + +function collectVueFiles(directory) { + return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => { + const target = path.join(directory, entry.name) + return entry.isDirectory() ? collectVueFiles(target) : entry.name.endsWith('.vue') ? [target] : [] + }) +} + +function lineNumber(source, offset) { + return source.slice(0, offset).split('\n').length +} + +function hasLiteralAttribute(tag, name) { + return new RegExp(`\\s${name}(?:\\s|=|/?>)`).test(tag) +} + +function isEditableNativeTextInput(tag) { + if (hasLiteralAttribute(tag, 'disabled') || hasLiteralAttribute(tag, 'readonly')) return false + const type = tag.match(/\stype\s*=\s*["']([^"']+)["']/)?.[1]?.toLowerCase() ?? 'text' + return ['text', 'search', 'email', 'tel', 'url', 'password'].includes(type) +} + +test('all editable text inputs provide a user-facing placeholder', () => { + const violations = [] + + for (const file of collectVueFiles(sourceRoot)) { + const source = readFileSync(file, 'utf8') + const template = source.match(/]*)?>([\s\S]*)<\/template>/)?.[1] ?? '' + const withoutComments = template.replace(//g, '') + const attributeContent = String.raw`(?:[^>"']|"[^"]*"|'[^']*')*` + const tagPattern = new RegExp(`|<(?:input|textarea)\\b${attributeContent}/?>`, 'g') + + for (const match of withoutComments.matchAll(tagPattern)) { + const tag = match[0] + const isElementInput = tag.startsWith('
- - - + + +
- - + +