Проверяем инструкцию о мерах пожарной безопасности кодом: линтер для обязательных разделов
Если вы делаете систему документооборота, конструктор документов или внутренний портал по охране труда, рано или поздно появится задача: пользователь загружает инструкцию о мерах пожарной безопасности, а система должна сказать, всё ли в ней на месте. Полностью автоматизировать экспертизу нельзя, но поймать типовые ошибки — вполне. Разберём простой линтер на JavaScript.
Откуда берутся правила
Инструкция обязательна для каждого здания и сооружения организации (п. 2 Правил противопожарного режима, постановление Правительства РФ № 1479). Требования к содержанию собраны в разделе XVIII этих Правил. Отсюда можно взять список блоков, которые должны быть в документе.
Шаг 1: описываем обязательные разделы
Заголовки в реальных документах пишут по-разному, поэтому для каждого раздела храним несколько шаблонов:
const REQUIRED_SECTIONS = [ { id: 'premises', title: 'Содержание помещений и путей эвакуации', patterns: [/содержани[ея].*(помещени|территори)/i, /эвакуационн/i] }, { id: 'equipment', title: 'Эксплуатация оборудования', patterns: [/эксплуатаци.*(оборудовани|электро)/i] }, { id: 'storage', title: 'Хранение пожароопасных материалов', patterns: [/хранени/i] }, { id: 'smoking', title: 'Места для курения и огневых работ', patterns: [/курени/i, /огнев\w* работ/i] }, { id: 'waste', title: 'Сбор и удаление горючих отходов', patterns: [/отход/i] }, { id: 'closing', title: 'Осмотр помещений в конце дня', patterns: [/осмотр/i] }, { id: 'fireAction', title: 'Действия работников при пожаре', patterns: [/(действи|обязанност).*при пожаре/i] }, ]; Раздел считается найденным, если совпал хотя бы один шаблон.
Шаг 2: ловим устаревшие ссылки
Самая частая ошибка — инструкция, переписанная из старого шаблона со ссылками на ППР № 390. Эти правила отменены с 2021 года, и проверяющий сразу считает такой документ неактуальным.
const OUTDATED = [ { re: /(ППР|постановлени\w*)[^.\n]{0,40}№\s*390/i, message: 'Ссылка на отменённые ППР № 390 — замените на ППР № 1479' }, ]; Шаг 3: собираем отчёт
function lintInstruction(text) { const missing = REQUIRED_SECTIONS .filter(s => !s.patterns.some(re => re.test(text))) .map(s => s.title); const warnings = OUTDATED .filter(rule => rule.re.test(text)) .map(rule => rule.message); if (!/1479/.test(text)) warnings.push('Нет ссылки на действующие ППР № 1479'); if (!/утвержд/i.test(text)) warnings.push('Не видно отметки об утверждении руководителем'); return { ok: missing.length === 0 && warnings.length === 0, missing, warnings }; } lintInstruction(fs.readFileSync('instrukciya.txt', 'utf8')); // { ok: false, // missing: ['Сбор и удаление горючих отходов'], // warnings: ['Ссылка на отменённые ППР № 390 — замените на ППР № 1479'] } Текст из DOCX удобно получить, например, библиотекой mammoth (extractRawText), из PDF — pdf-parse.
Чего линтер не проверит
- Привязку к объекту. Инструкция может содержать все разделы и при этом описывать чужое здание. Здесь помогает только человек, который знает объект: какие там помещения, оборудование, пути эвакуации.
- Специфику типа объекта. У кафе важны кухня и газ, у склада — правила складирования, у магазина — эвакуация покупателей. Можно добавить наборы правил по классу функциональной пожарной опасности, но это уже следующий шаг.
- Ознакомление персонала. Подписи сотрудников живут в отдельном журнале или листе, а не в тексте инструкции.
Поэтому результат линтера лучше показывать как подсказки для автора документа, а не как вердикт «соответствует / не соответствует».
Справочный материал
Полный перечень блоков, особенности инструкции для магазина, офиса, кафе и склада и разбор частых ошибок есть в статье инструкция о мерах пожарной безопасности на Protiv-Pozhara.ru. Из неё удобно брать формулировки для подсказок в интерфейсе.