fix: complete editable input hints
This commit is contained in:
@@ -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(/<template(?:\s[^>]*)?>([\s\S]*)<\/template>/)?.[1] ?? ''
|
||||
const withoutComments = template.replace(/<!--[\s\S]*?-->/g, '')
|
||||
const attributeContent = String.raw`(?:[^>"']|"[^"]*"|'[^']*')*`
|
||||
const tagPattern = new RegExp(`<el-input(?!-number)\\b${attributeContent}/?>|<(?:input|textarea)\\b${attributeContent}/?>`, 'g')
|
||||
|
||||
for (const match of withoutComments.matchAll(tagPattern)) {
|
||||
const tag = match[0]
|
||||
const isElementInput = tag.startsWith('<el-input')
|
||||
const editable = isElementInput
|
||||
? !hasLiteralAttribute(tag, 'disabled') && !hasLiteralAttribute(tag, 'readonly')
|
||||
: isEditableNativeTextInput(tag)
|
||||
|
||||
if (editable && !/\s:?(?:placeholder)\s*=/.test(tag)) {
|
||||
violations.push(`${path.relative(sourceRoot, file)}:${lineNumber(withoutComments, match.index ?? 0)} ${tag.replace(/\s+/g, ' ')}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert.deepEqual(violations, [], `Editable text inputs without placeholders:\n${violations.join('\n')}`)
|
||||
})
|
||||
Reference in New Issue
Block a user