check:no-fleet-names: names in any case, the plugin agents' names, and the translation catalogues scanned too; the self-test plants each
This commit is contained in:
parent
2f7eaae8e3
commit
59afad5a33
1 changed files with 20 additions and 9 deletions
|
|
@ -7,9 +7,10 @@
|
|||
* which request a choice answered, which QA round found it. The technical fact belongs in the comment; the person,
|
||||
* the request and the date-stamped round do not. A sweep removed every such line; this gate keeps the count at 0.
|
||||
*
|
||||
* SCANS every tracked text file EXCEPT research data (data/, plugin-designs/<plugin>/data/), build output
|
||||
* (public/) and the translation catalogues (library/i18n/locales/: UI strings in 11 languages, where a short
|
||||
* pattern can be an ordinary word). Three classes:
|
||||
* SCANS every tracked text file EXCEPT research data (data/, plugin-designs/<plugin>/data/) and build output
|
||||
* (public/). The translation catalogues ARE scanned: a name can hide in a string as well as a comment, and a
|
||||
* translation that ever collides with a short name is allowed by its line, not by skipping the folder. Names match
|
||||
* in any case. Three classes:
|
||||
* 1. a build-team member's name (the fleet's agent names);
|
||||
* 2. a per-user attribution (the words "per" and "user" in a row: a request credited to a person);
|
||||
* 3. a dated QA-round tag (a lowercase or uppercase QA label followed by a 20xx date).
|
||||
|
|
@ -25,13 +26,16 @@ import { fileURLToPath } from 'node:url'
|
|||
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')
|
||||
|
||||
// Built from parts so this file does not match itself line by line.
|
||||
const NAMES = ['dx-' + 'shepherd', 'exp-' + 'shepherd', 'go-' + 'int', 'msg-' + 'agent', 'regions-' + 'plugin', 're' + 'ga']
|
||||
const NAMES = ['dx-' + 'shepherd', 'exp-' + 'shepherd', 'go-' + 'int', 'msg-' + 'agent', 're' + 'ga']
|
||||
// The plugin agents are named <plugin>-plugin; the folders and bundles never carry that suffix.
|
||||
const PLUGIN_AGENTS = ['deep-research', 'prayer-progress', 'poster-design', 'country-posters', 'wall-of-people-groups',
|
||||
'simpleresearch', 'regions', 'big-picture', 'bible-poster', 'upg100', 'gospel', 'cities'].map((p) => p + '-' + 'plugin')
|
||||
const CLASSES = [
|
||||
['a build-team member named', new RegExp('\\b(' + NAMES.join('|') + ')\\b')],
|
||||
['a build-team member named', new RegExp('\\b(' + NAMES.concat(PLUGIN_AGENTS).join('|') + ')\\b', 'i')],
|
||||
['a per-user attribution', new RegExp('\\bper ' + 'user\\b', 'i')],
|
||||
['a dated QA tag', new RegExp('\\(q' + 'a:|\\bq' + 'a: ?20\\d\\d-|\\bQ' + 'A 20\\d\\d-\\d\\d')],
|
||||
]
|
||||
const SKIP = [/^data\//, /^public\//, /^plugin-designs\/[^/]+\/data\//, /^library\/i18n\/locales\//, /\/node_modules\//]
|
||||
const SKIP = [/^data\//, /^public\//, /^plugin-designs\/[^/]+\/data\//, /\/node_modules\//]
|
||||
const TEXT = /\.(m?js|cjs|ts|vue|html|css|json|md|sh|go|py|ya?ml|txt|svg)$|(^|\/)(Dockerfile|\.gitignore|\.gitattributes)$/
|
||||
// { file, line: RegExp matching the WHOLE allowed line, why }. A detector that must name what it detects goes here,
|
||||
// one line at a time. Empty today.
|
||||
|
|
@ -53,13 +57,17 @@ function trackedFiles() {
|
|||
|
||||
if (process.argv.includes('--self-test')) {
|
||||
const planted = [
|
||||
['measured by ' + NAMES[5] + ' at 390', 1],
|
||||
['measured by ' + NAMES[4] + ' at 390', 1],
|
||||
['(' + NAMES[0] + "'s ruling)", 1],
|
||||
['// Per ' + 'user 2026-05-02: drop the prefix', 1],
|
||||
['/* fits the band (q' + 'a: 2026-05-02 iter-9) */', 1],
|
||||
['// Q' + 'A 2026-04-27: rows match desktop', 1],
|
||||
['// the drawer opens from the right in ar', 0],
|
||||
['// a user of the map can pick a language', 0],
|
||||
['// ' + NAMES[4].toUpperCase().slice(0, 1) + NAMES[4].slice(1) + ' measured it at 390', 1],
|
||||
['(' + NAMES[0].toUpperCase() + "'s call)", 1],
|
||||
['// on ' + PLUGIN_AGENTS[9] + "'s argument", 1],
|
||||
['// the ' + PLUGIN_AGENTS[3].replace('-' + 'plugin', '') + ' bundle', 0],
|
||||
['// the irrigation (reg' + 'ar) field', 0],
|
||||
]
|
||||
let bad = 0
|
||||
|
|
@ -69,14 +77,17 @@ if (process.argv.includes('--self-test')) {
|
|||
console.log(` ${ok ? 'ok ' : 'BAD'} ${want ? 'caught' : 'clean '}: ${line}`)
|
||||
if (!ok) bad++
|
||||
}
|
||||
// A name inside a translation catalogue is scanned like any other file.
|
||||
const localeFile = 'library/i18n/locales/en/x.json'
|
||||
if (SKIP.some((re) => re.test(localeFile)) || scanText('{ "note": "by ' + NAMES[0] + '" }', localeFile).length !== 1) { console.log(' BAD locales: a name in a catalogue was not caught'); bad++ }
|
||||
// The allowlist is per LINE: an allowed line passes, a different flagged line in the SAME file still fails.
|
||||
const allow = [{ file: 'd.mjs', line: /^const PATTERN = .*detects$/, why: 'self-test' }]
|
||||
const allowedLine = 'const PATTERN = "' + NAMES[0] + '" // detects'
|
||||
if (scanText(allowedLine, 'd.mjs', allow).length !== 0) { console.log(' BAD allowlist: an allowed line was flagged'); bad++ }
|
||||
if (scanText(allowedLine + '\n// measured by ' + NAMES[5], 'd.mjs', allow).length !== 1) { console.log(' BAD allowlist: a new name in an allowlisted file passed'); bad++ }
|
||||
if (scanText(allowedLine + '\n// measured by ' + NAMES[4], 'd.mjs', allow).length !== 1) { console.log(' BAD allowlist: a new name in an allowlisted file passed'); bad++ }
|
||||
if (scanText(allowedLine, 'other.mjs', allow).length !== 1) { console.log(' BAD allowlist: the allowed line passed in another file'); bad++ }
|
||||
if (bad) { console.error(`NO-FLEET-NAMES SELF-TEST: FAIL — ${bad} line(s) judged wrong.`); process.exit(1) }
|
||||
console.log(`NO-FLEET-NAMES SELF-TEST: PASS — ${planted.filter((p) => p[1]).length} planted lines caught, ${planted.filter((p) => !p[1]).length} clean lines passed, the per-line allowlist holds (3 cases).`)
|
||||
console.log(`NO-FLEET-NAMES SELF-TEST: PASS — ${planted.filter((p) => p[1]).length} planted lines caught, ${planted.filter((p) => !p[1]).length} clean lines passed, the per-line allowlist holds (3 cases), catalogues are scanned.`)
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue