|
| 1 | +/*--------------------------------------------------------------------------------------------- |
| 2 | + * Copyright (c) Red Hat, Inc. All rights reserved. |
| 3 | + * Licensed under the MIT License. See License.txt in the project root for license information. |
| 4 | + *--------------------------------------------------------------------------------------------*/ |
| 5 | +'use strict'; |
| 6 | + |
| 7 | +/** |
| 8 | + * Pattern that matches a `# yaml-lint-disable` comment. |
| 9 | + * |
| 10 | + * Usage in YAML files: |
| 11 | + * # yaml-lint-disable ← suppress ALL diagnostics on the next line |
| 12 | + * # yaml-lint-disable Incorrect type ← suppress diagnostics whose message contains "Incorrect type" |
| 13 | + * # yaml-lint-disable Incorrect type, not accepted ← suppress diagnostics matching any of the substrings |
| 14 | + * |
| 15 | + * Capture group 1 (optional) contains the comma-separated list of message |
| 16 | + * substrings to match against. If absent, all diagnostics are suppressed. |
| 17 | + */ |
| 18 | +export const YAML_LINT_DISABLE_PATTERN = /^\s*#\s*yaml-lint-disable\b(.*)$/; |
| 19 | + |
| 20 | +/** |
| 21 | + * A callback that returns the text content of a given zero-based line number, |
| 22 | + * or `undefined` if the line does not exist. |
| 23 | + */ |
| 24 | +export type GetLineText = (line: number) => string | undefined; |
| 25 | + |
| 26 | +/** |
| 27 | + * Parse the text after `yaml-lint-disable` into an array of trimmed, |
| 28 | + * lower-cased message substrings. Returns an empty array when no |
| 29 | + * specifiers are provided (meaning "suppress all"). |
| 30 | + */ |
| 31 | +export function parseDisableSpecifiers(raw: string): string[] { |
| 32 | + const trimmed = raw.trim(); |
| 33 | + if (!trimmed) { |
| 34 | + return []; |
| 35 | + } |
| 36 | + return trimmed |
| 37 | + .split(',') |
| 38 | + .map((s) => s.trim().toLowerCase()) |
| 39 | + .filter((s) => s.length > 0); |
| 40 | +} |
| 41 | + |
| 42 | +/** |
| 43 | + * Determine whether a diagnostic should be suppressed based on the |
| 44 | + * specifiers from a `# yaml-lint-disable` comment. |
| 45 | + * |
| 46 | + * @param specifiers - Parsed specifiers (empty means suppress all). |
| 47 | + * @param diagnosticMessage - The diagnostic's message text. |
| 48 | + * @returns `true` if the diagnostic should be suppressed. |
| 49 | + */ |
| 50 | +export function shouldSuppressDiagnostic(specifiers: string[], diagnosticMessage: string): boolean { |
| 51 | + if (specifiers.length === 0) { |
| 52 | + return true; // no specifiers → suppress everything |
| 53 | + } |
| 54 | + const lowerMessage = diagnosticMessage.toLowerCase(); |
| 55 | + return specifiers.some((spec) => lowerMessage.includes(spec)); |
| 56 | +} |
| 57 | + |
| 58 | +/** |
| 59 | + * Filters an array of diagnostics, removing any whose starting line is |
| 60 | + * immediately preceded by a `# yaml-lint-disable` comment. |
| 61 | + * |
| 62 | + * When the comment includes one or more comma-separated message substrings, |
| 63 | + * only diagnostics whose message contains at least one of those substrings |
| 64 | + * (case-insensitive) are suppressed. Without specifiers, all diagnostics |
| 65 | + * on the next line are suppressed. |
| 66 | + * |
| 67 | + * @param diagnostics - The diagnostics to filter. |
| 68 | + * @param getStartLine - Extracts the zero-based starting line number from a diagnostic. |
| 69 | + * @param getMessage - Extracts the message string from a diagnostic. |
| 70 | + * @param getLineText - Returns the text of a document line by its zero-based index, |
| 71 | + * or `undefined` if the line is out of range. |
| 72 | + * @returns A new array containing only the diagnostics that are not suppressed. |
| 73 | + */ |
| 74 | +export function filterSuppressedDiagnostics<T>( |
| 75 | + diagnostics: T[], |
| 76 | + getStartLine: (diag: T) => number, |
| 77 | + getMessage: (diag: T) => string, |
| 78 | + getLineText: GetLineText |
| 79 | +): T[] { |
| 80 | + return diagnostics.filter((diag) => { |
| 81 | + const line = getStartLine(diag); |
| 82 | + if (line === 0) { |
| 83 | + return true; // no preceding line to check |
| 84 | + } |
| 85 | + const prevLineText = getLineText(line - 1); |
| 86 | + if (prevLineText === undefined) { |
| 87 | + return true; // couldn't read the line — keep the diagnostic |
| 88 | + } |
| 89 | + const match = YAML_LINT_DISABLE_PATTERN.exec(prevLineText); |
| 90 | + if (!match) { |
| 91 | + return true; // no disable comment — keep the diagnostic |
| 92 | + } |
| 93 | + const specifiers = parseDisableSpecifiers(match[1]); |
| 94 | + return !shouldSuppressDiagnostic(specifiers, getMessage(diag)); |
| 95 | + }); |
| 96 | +} |
0 commit comments