Проверка согласованности
Две независимые команды только для чтения, которые объединяет не тема, а общий фундамент: обе сканируют текст/конвенцию вместо разбора AST, и обе проверяют, соответствует ли одна часть проекта другой — scripts-check сверяет scripts из package.json с тем, что реально вызывают README/CI, orphan-tests сверяет тестовый файл с исходником, который он якобы покрывает.
scripts-check
Сверяет scripts из package.json с README/доками и .github/workflows/*.yml — упоминание скрипта, которого не существует, и, как более слабый сигнал, скрипт, который нигде не задокументирован.
devtoolz scripts-check [dir] [options]Реальный вывод — README с опечаткой в имени скрипта, и два реальных скрипта, которые нигде не задокументированы:
Checked 1 source against package.json's scripts.
3 problems found:
README.md:4 buld mentioned here, but not in package.json scripts
package.json:4 build in package.json scripts, but not mentioned anywhere checked
package.json:6 deploy in package.json scripts, but not mentioned anywhere checkedИсправьте опечатку (buld → build), и первая строка исчезнет. Документировать ли остальные два — решение человека, не жёсткое правило.
Два направления — разная планка того, что считается упоминанием
Направление 1 (упомянутый скрипт, которого не существует — высокая ценность) распознаёт только формы с явным run: npm run X/npm run-script X, yarn run X, pnpm run X, плюс npm-шные npm test/npm start без него. Без явного run нет способа отличить yarn X (скрипт) от настоящей yarn-подкоманды (yarn add, yarn install) — извлекать произвольное имя из такой формы было бы просто шумом.
Направление 2 (объявленный скрипт, который никто не упоминает — более слабый сигнал) может позволить себе и голые yarn X/pnpm X формы, поскольку проверяется уже известное конкретное имя, а не извлекается произвольное из свободного текста. Чистый прогон:
Checked 1 source against package.json's scripts.
Nothing to see here. Suspiciously clean, even.Зарезервированные скрипты жизненного цикла исключены из направления 2
prepublishOnly, preinstall, postinstall, prepare, и любой pre*/post*-скрипт, для которого реально объявлен парный скрипт (prebuild, когда есть build) — npm вызывает их сам, документировать их «для человека» незачем.
Шаг CI со своим working-directory: принадлежит другому package.json
Поддиректория demo/ со своим package.json и своим скриптом test:e2e, вызываемая из CI-джоба с working-directory: demo, корректно понимается как вне области действия корневого package.json, который проверяет команда — не репортится как отсутствующая.
Опции
[dir]
Директория пакета для проверки (по умолчанию: .).
--file <path>
Markdown/doc-файл для проверки, относительно [dir] (повторяемый) — по умолчанию: README.md.
Пример:
devtoolz scripts-check # package.json в текущей директории
devtoolz scripts-check path/to/package # конкретная директория
devtoolz scripts-check --file docs/deploying.md # проверить дополнительный докorphan-tests
Находит тестовые файлы, у которых пропал исходник — переименовали или удалили source, тест остался и всё ещё зелёный, просто ничего реального больше не проверяет.
devtoolz orphan-tests [paths...] [options]Реальный вывод — parseQuery.ts переименовали/удалили, его тест остался:
Scanned 3 files.
1 orphan test found:
src/parseQuery.test.ts orphan no matching source found (tried .ts, .tsx, .js, .jsx, .mjs, .cjs, .vue)Надёжна только при простом соглашении об именовании
Совмещённый вариант — Foo.test.ts рядом с Foo.ts — включая один уровень глубже, в сестринской __tests__/tests/test/spec/specs-директории (src/adapters/__tests__/http.test.ts рядом с src/adapters/http.ts). Чистый прогон против такой раскладки:
Scanned 2 files.
Nothing to see here. Suspiciously clean, even.Не каждый проект следует одной из этих форм — тот, чьи имена тестов описательные, а не привязаны 1:1 к source-файлу (feature-component.test.ts, тестирующий components/feature.vue), честно вне того, что эта команда может проверить надёжно, и будет шуметь под ней. Это заявленное ограничение, а не баг, который нужно обходить.
Зеркальная раскладка — отдельные корни для source и test
--source-dir/--test-dir (всегда указываются вместе) проверяют путь теста против того же относительного пути под другим корнем, вместо той же директории:
Scanned 2 files.
1 orphan test found:
tests/legacyParser.test.ts orphan no matching source found (tried .ts, .tsx, .js, .jsx, .mjs, .cjs, .vue)Сценарные/интеграционные тесты — известный ложный срабатыватель
Тест, проверяющий комбинацию модулей, или несколько сценариев одного компонента, без единственного собственного source-файла (hydration.test.ts, ssr.test.ts — разные ракурсы одного и того же компонента), всегда будет выглядеть осиротевшим под строгим правилом этой команды «один файл — один source». --ignore <glob> — документированный способ его исключить, команда не пытается угадывать, какие упоминания «настоящие».
Опции
[paths...]
Файлы/директории для обработки — только для совмещённого режима (по умолчанию: текущая директория).
--cwd <path>
Относительно чего резолвятся корневые пути.
--ext <list>
Список расширений через запятую, рассматриваемых как возможные тестовые файлы. По умолчанию: .ts,.tsx,.js,.jsx,.mjs,.cjs.
--test-suffix <list>
Список суффиксов через запятую, помечающих файл как тестовый. По умолчанию: .test,.spec.
--source-ext <list>
Список расширений через запятую, перебираемых в поисках соответствующего source-файла. По умолчанию: .ts,.tsx,.js,.jsx,.mjs,.cjs,.vue.
--source-dir <path> / --test-dir <path>
Зеркальная раскладка — корень source и корень test, оба относительно --cwd. Указываются только вместе.
--ignore <glob>
Дополнительный паттерн игнорирования (повторяемый) поверх встроенных по умолчанию — способ исключить известный сценарный/интеграционный тест.
--no-respect-gitignore
Не учитывать также .gitignore проекта.
Пример:
devtoolz orphan-tests src # совмещённый режим, включая __tests__/tests
devtoolz orphan-tests --source-dir src --test-dir tests # зеркальная раскладка
devtoolz orphan-tests src --ignore src/integration.test.ts # исключить известный сценарный тест