All files / src/compiler/utils extract_svelte_ignore.js

100% Statements 103/103
100% Branches 23/23
100% Functions 2/2
100% Lines 101/101

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 1022x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 616x 616x 120x 120x 120x 120x 120x 120x 120x 352x 6x 6x 6x 6x 6x 3x 3x 3x 3x 3x 3x 3x 3x 3x 2x 3x 1x 1x 1x 3x 6x 6x 6x 6x 6x 333x 114x 114x 131x 131x 131x 131x 131x 27x 27x 27x 12x 12x 27x 131x 114x 120x 120x 120x 2x 2x 2x 2x 2x 2x 2x 4x 4x 3x 3x 3x 3x 3x 4x 4x 1x 1x 4x 3x 3x 3x  
import fuzzymatch from '../phases/1-parse/utils/fuzzymatch.js';
import * as w from '../warnings.js';
 
const regex_svelte_ignore = /^\s*svelte-ignore\s/;
 
/** @type {Record<string, string>} Map of legacy code -> new code */
const replacements = {
	'non-top-level-reactive-declaration': 'reactive_declaration_invalid_placement',
	'module-script-reactive-declaration': 'reactive_declaration_module_script',
	'empty-block': 'block_empty',
	'avoid-is': 'attribute_avoid_is',
	'invalid-html-attribute': 'attribute_invalid_property_name',
	'a11y-structure': 'a11y_figcaption_parent',
	'illegal-attribute-character': 'attribute_illegal_colon',
	'invalid-rest-eachblock-binding': 'bind_invalid_each_rest',
	'unused-export-let': 'export_let_unused'
};
 
/**
 * @param {number} offset
 * @param {string} text
 * @param {boolean} runes
 * @returns {string[]}
 */
export function extract_svelte_ignore(offset, text, runes) {
	const match = regex_svelte_ignore.exec(text);
	if (!match) return [];
 
	let length = match[0].length;
	offset += length;
 
	/** @type {string[]} */
	const ignores = [];
 
	if (runes) {
		// Warnings have to be separated by commas, everything after is interpreted as prose
		for (const match of text.slice(length).matchAll(/([\w$-]+)(,)?/gm)) {
			const code = match[1];
 
			if (w.codes.includes(code)) {
				ignores.push(code);
			} else {
				const replacement = replacements[code] ?? code.replace(/-/g, '_');
 
				// The type cast is for some reason necessary to pass the type check in CI
				const start = offset + /** @type {number} */ (match.index);
				const end = start + code.length;
 
				if (w.codes.includes(replacement)) {
					w.legacy_code({ start, end }, code, replacement);
				} else {
					const suggestion = fuzzymatch(code, w.codes);
					w.unknown_code({ start, end }, code, suggestion);
				}
			}
 
			if (!match[2]) {
				break;
			}
		}
	} else {
		// Non-runes mode: lax parsing, backwards compat with old codes
		for (const match of text.slice(length).matchAll(/[\w$-]+/gm)) {
			const code = match[0];
 
			ignores.push(code);
 
			if (!w.codes.includes(code)) {
				const replacement = replacements[code] ?? code.replace(/-/g, '_');
 
				if (w.codes.includes(replacement)) {
					ignores.push(replacement);
				}
			}
		}
	}
 
	return ignores;
}
 
/**
 * Replaces legacy svelte-ignore codes with new codes.
 * @param {string} text
 * @returns {string}
 */
export function migrate_svelte_ignore(text) {
	const match = regex_svelte_ignore.exec(text);
	if (!match) return text;
 
	const length = match[0].length;
	return (
		text.substring(0, length) +
		text.substring(length).replace(/\w+-\w+(-\w+)*/g, (code, _, idx) => {
			let replacement = replacements[code] ?? code.replace(/-/g, '_');
			if (/\w+-\w+/.test(text.substring(length + idx + code.length))) {
				replacement += ',';
			}
			return replacement;
		})
	);
}