feat: warn on unknown warning codes in runes mode

pull/11549/head
Rich Harris 2 years ago
parent 7e9b109de6
commit ede63715ec

@ -0,0 +1,5 @@
## unknown_code
> `%code%` is not a recognised code
> `%code%` is not a recognised code (did you mean `%suggestion%`?)

@ -61,7 +61,7 @@ function transform(name, dest) {
const comments = [];
const ast = acorn.parse(source, {
let ast = acorn.parse(source, {
ecmaVersion: 'latest',
sourceType: 'module',
onComment: (block, value, start, end) => {
@ -80,7 +80,7 @@ function transform(name, dest) {
}
});
walk(ast, null, {
ast = walk(ast, null, {
_(node, { next }) {
let comment;
@ -100,6 +100,18 @@ function transform(name, dest) {
node.trailingComments = [comments.shift()];
}
}
},
// @ts-expect-error
Identifier(node, context) {
if (node.name === 'CODES') {
return {
type: 'ArrayExpression',
elements: Object.keys(messages[name]).map((code) => ({
type: 'Literal',
value: code
}))
};
}
}
});

@ -42,6 +42,8 @@ function w(node, code, message) {
});
}
export const codes = CODES;
/**
* MESSAGE
* @param {null | NodeLike} node

@ -201,7 +201,7 @@ export function convert(source, ast) {
Comment(node) {
return {
...node,
ignores: extract_svelte_ignore(node.data)
ignores: extract_svelte_ignore(node.start, node.data, false)
};
},
ComplexSelector(node) {

@ -559,11 +559,17 @@ export function analyze_component(root, source, options) {
prune(analysis.css.ast, element);
}
if (
!analysis.css.ast.content.comment ||
!extract_svelte_ignore(analysis.css.ast.content.comment.data).includes('css_unused_selector')
) {
warn_unused(analysis.css.ast);
const { comment } = analysis.css.ast.content;
if (comment) {
const ignores = extract_svelte_ignore(comment.start, comment.data, analysis.runes);
const should_ignore =
ignores.includes('css_unused_selector') ||
(!runes && ignores.includes('css-unused-selector'));
if (!should_ignore) {
warn_unused(analysis.css.ast);
}
}
outer: for (const element of analysis.elements) {
@ -1102,7 +1108,8 @@ const common_visitors = {
const ignores = [];
for (const comment of comments) {
ignores.push(...extract_svelte_ignore(comment.value));
const start = /** @type {any} */ (comment).start + 2;
ignores.push(...extract_svelte_ignore(start, comment.value, context.state.analysis.runes));
}
if (ignores.length > 0) {
@ -1133,7 +1140,11 @@ const common_visitors = {
}
if (child.type === 'Comment') {
ignores.push(...extract_svelte_ignore(child.data));
const start =
child.start +
(context.state.analysis.source.slice(child.start, child.start + 4) === '<!--' ? 4 : 2);
ignores.push(...extract_svelte_ignore(start, child.data, context.state.analysis.runes));
} else {
const combined_ignores = new Set(context.state.ignores);
for (const ignore of ignores) combined_ignores.add(ignore);

@ -1,17 +1,45 @@
import { regex_whitespace } from '../phases/patterns.js';
import * as w from '../warnings.js';
const regex_svelte_ignore = /^\s*svelte-ignore\s+([\s\S]+)\s*$/m;
const regex_svelte_ignore = /^\s*svelte-ignore\s/;
/** @type {Record<string, string>} */
const replacements = {
'non-top-level-reactive-declaration': 'reactive_declaration_invalid_placement'
};
/**
* @param {number} offset
* @param {string} text
* @param {boolean} runes
* @returns {string[]}
*/
export function extract_svelte_ignore(text) {
export function extract_svelte_ignore(offset, text, runes) {
const match = regex_svelte_ignore.exec(text);
return match
? match[1]
.split(regex_whitespace)
.map(/** @param {any} x */ (x) => x.trim())
.filter(Boolean)
: [];
if (!match) return [];
let start = match[0].length;
offset += start;
/** @type {string[]} */
const ignores = [];
for (const match of text.slice(start).matchAll(/\S+/gm)) {
const code = match[0];
console.log({ code, runes, codes: w.codes });
if (runes && !w.codes.includes(code)) {
const suggestion = replacements[code] || code.replace(/-/g, '_');
if (w.codes.includes(suggestion)) {
w.unknown_code({ start: offset, end: offset + code.length }, code, suggestion);
} else {
w.unknown_code({ start: offset, end: offset + code.length }, code);
}
}
ignores.push(code);
}
return ignores;
}

@ -40,6 +40,78 @@ function w(node, code, message) {
});
}
export const codes = [
"a11y_accesskey",
"a11y_aria_activedescendant_has_tabindex",
"a11y_aria_attributes",
"a11y_autocomplete_valid",
"a11y_autofocus",
"a11y_click_events_have_key_events",
"a11y_distracting_elements",
"a11y_figcaption_index",
"a11y_figcaption_parent",
"a11y_hidden",
"a11y_img_redundant_alt",
"a11y_incorrect_aria_attribute_type",
"a11y_incorrect_aria_attribute_type_boolean",
"a11y_incorrect_aria_attribute_type_id",
"a11y_incorrect_aria_attribute_type_idlist",
"a11y_incorrect_aria_attribute_type_integer",
"a11y_incorrect_aria_attribute_type_token",
"a11y_incorrect_aria_attribute_type_tokenlist",
"a11y_incorrect_aria_attribute_type_tristate",
"a11y_interactive_supports_focus",
"a11y_invalid_attribute",
"a11y_label_has_associated_control",
"a11y_media_has_caption",
"a11y_misplaced_role",
"a11y_misplaced_scope",
"a11y_missing_attribute",
"a11y_missing_content",
"a11y_mouse_events_have_key_events",
"a11y_no_abstract_role",
"a11y_no_interactive_element_to_noninteractive_role",
"a11y_no_noninteractive_element_interactions",
"a11y_no_noninteractive_element_to_interactive_role",
"a11y_no_noninteractive_tabindex",
"a11y_no_redundant_roles",
"a11y_no_static_element_interactions",
"a11y_positive_tabindex",
"a11y_role_has_required_aria_props",
"a11y_role_supports_aria_props",
"a11y_role_supports_aria_props_implicit",
"a11y_unknown_aria_attribute",
"a11y_unknown_role",
"unknown_code",
"options_deprecated_accessors",
"options_deprecated_immutable",
"options_missing_custom_element",
"options_removed_enable_sourcemap",
"options_removed_hydratable",
"options_removed_loop_guard_timeout",
"options_renamed_ssr_dom",
"derived_iife",
"export_let_unused",
"non_reactive_update",
"perf_avoid_inline_class",
"perf_avoid_nested_class",
"reactive_declaration_invalid_placement",
"reactive_declaration_module_script",
"state_referenced_locally",
"store_rune_conflict",
"css_unused_selector",
"attribute_avoid_is",
"attribute_global_event_reference",
"attribute_illegal_colon",
"attribute_invalid_property_name",
"bind_invalid_each_rest",
"block_empty",
"component_name_lowercase",
"element_invalid_self_closing_tag",
"event_directive_deprecated",
"slot_element_deprecated"
];
/**
* Avoid using accesskey
* @param {null | NodeLike} node
@ -414,6 +486,16 @@ export function a11y_unknown_role(node, role, suggestion) {
w(node, "a11y_unknown_role", suggestion ? `Unknown role '${role}'. Did you mean '${suggestion}'?` : `Unknown role '${role}'`);
}
/**
* `%code%` is not a recognised code (did you mean `%suggestion%`?)
* @param {null | NodeLike} node
* @param {string} code
* @param {string | undefined | null} [suggestion]
*/
export function unknown_code(node, code, suggestion) {
w(node, "unknown_code", suggestion ? `\`${code}\` is not a recognised code (did you mean \`${suggestion}\`?)` : `\`${code}\` is not a recognised code`);
}
/**
* The `accessors` option has been deprecated. It will have no effect in runes mode
* @param {null | NodeLike} node

Loading…
Cancel
Save