chore: markdown warnings (#11302)

* rename warnings.js to warnings-tmp.js

* start porting warnings

* centralise stuff

* finish porting warnings

* tidy up

* get messages into JSDoc annotations

* prettier

* lint
pull/11303/head
Rich Harris 1 year ago committed by GitHub
parent 5405ec6c91
commit 7b55bd4d89
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -4,6 +4,7 @@ packages/**/npm/**/*
packages/**/config/*.js
packages/svelte/messages/**/*.md
packages/svelte/src/compiler/errors.js
packages/svelte/src/compiler/warnings.js
packages/svelte/tests/**/*.svelte
packages/svelte/tests/**/_expected*
packages/svelte/tests/**/_actual*

@ -0,0 +1,171 @@
## a11y_aria_attributes
<%name%> should not have aria-* attributes
## a11y_unknown_aria_attribute
Unknown aria attribute 'aria-%attribute%'
## a11y_unknown_aria_attribute_suggestion
Unknown aria attribute 'aria-%attribute%'. Did you mean '%suggestion%'?
## a11y_hidden
<%name%> element should not be hidden
## a11y_incorrect_aria_attribute_type_boolean
The value of '%attribute%' must be either 'true' or 'false'
## a11y_incorrect_aria_attribute_type_integer
The value of '%attribute%' must be an integer
## a11y_incorrect_aria_attribute_type_id
The value of '%attribute%' must be a string that represents a DOM element ID
## a11y_incorrect_aria_attribute_type_idlist
The value of '%attribute%' must be a space-separated list of strings that represent DOM element IDs
## a11y_incorrect_aria_attribute_type_tristate
The value of '%attribute%' must be exactly one of true, false, or mixed
## a11y_incorrect_aria_attribute_type_token
The value of '%attribute%' must be exactly one of %values%
## a11y_incorrect_aria_attribute_type_tokenlist
The value of '%attribute%' must be a space-separated list of one or more of %values%
## a11y_incorrect_aria_attribute_type
The value of '%attribute%' must be of type %type%
## a11y_aria_activedescendant_has_tabindex
Elements with attribute aria-activedescendant should have tabindex value
## a11y_misplaced_role
<%name%> should not have role attribute
## a11y_no_abstract_role
Abstract role '%role%' is forbidden
## a11y_unknown_role
Unknown role '%role%'
## a11y_unknown_role_suggestion
Unknown role '%role%'. Did you mean '%suggestion%'?
## a11y_no_redundant_roles
Redundant role '%role%'
## a11y_role_has_required_aria_props
Elements with the ARIA role "%role%" must have the following attributes defined: %props%
## a11y_interactive_supports_focus
Elements with the '%role%' interactive role must have a tabindex value.
## a11y_no_interactive_element_to_noninteractive_role
<%element%> cannot have role '%role%'
## a11y_no_noninteractive_element_to_interactive_role
Non-interactive element <%element%> cannot have interactive role '%role%'
## a11y_accesskey
Avoid using accesskey
## a11y_autofocus
Avoid using autofocus
## a11y_misplaced_scope
The scope attribute should only be used with <th> elements
## a11y_positive_tabindex
Avoid tabindex values above zero
## a11y_click_events_have_key_events
Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type="button"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.
## a11y_no_noninteractive_tabindex
noninteractive element cannot have nonnegative tabIndex value
## a11y_role_supports_aria_props
The attribute '%attribute%' is not supported by the role '%role%'
## a11y_role_supports_aria_props_implicit
The attribute '%attribute%' is not supported by the role '%role%'. This role is implicit on the element <%name%>
## a11y_no_noninteractive_element_interactions
Non-interactive element <%element%> should not be assigned mouse or keyboard event listeners.
## a11y_no_static_element_interactions
<%element%> with a %handler% handler must have an ARIA role
## a11y_invalid_attribute
'%href_value%' is not a valid %href_attribute% attribute
## a11y_missing_attribute
<%name%> element should have %article% %sequence% attribute
## a11y_autocomplete_valid
The value '%value%' is not supported by the attribute 'autocomplete' on element <input type="%type%">
## a11y_img_redundant_alt
Screenreaders already announce <img> elements as an image.
## a11y_label_has_associated_control
A form label must be associated with a control.
## a11y_media_has_caption
<video> elements must have a <track kind="captions">
## a11y_distracting_elements
Avoid <%name%> elements
## a11y_figcaption_parent
`<figcaption>` must be an immediate child of `<figure>`
## a11y_figcaption_index
`<figcaption>` must be first or last child of `<figure>`
## a11y_mouse_events_have_key_events
'%event%' event must be accompanied by '%accompanied_by%' event
## a11y_missing_content
<%name%> element should have child content

@ -0,0 +1,15 @@
## avoid_is
The "is" attribute is not supported cross-browser and should be avoided
## global_event_reference
You are referencing globalThis.%name%. Did you forget to declare a variable with that name?
## illegal_attribute_character
Attributes should not contain ':' characters to prevent ambiguity with Svelte directives
## invalid_html_attribute
'%wrong%' is not a valid HTML attribute. Did you mean '%right%'?

@ -0,0 +1,3 @@
## component_name_lowercase
<%name%> will be treated as an HTML element unless it begins with a capital letter

@ -0,0 +1,3 @@
## css_unused_selector
Unused CSS selector "%name%"

@ -0,0 +1,19 @@
## no_reactive_declaration
Reactive declarations only exist at the top level of the instance script
## module_script_reactive_declaration
All dependencies of the reactive declaration are declared in a module script and will not be reactive
## unused_export_let
Component has unused export property '%name%'. If it is for external reference only, please consider using `export const %name%`
## deprecated_slot_element
Using <slot> to render parent content is deprecated. Use {@render ...} tags instead.
## deprecated_event_handler
Using on:%name% to listen to the %name% event is is deprecated. Use the event attribute on%name% instead.

@ -0,0 +1,3 @@
## invalid_self_closing_tag
Self-closing HTML tags for non-void elements are ambiguous — use <%name% ...></%name%> rather than <%name% ... />

@ -0,0 +1,3 @@
## missing_custom_element_compile_option
The 'customElement' option is used when generating a custom element. Did you forget the 'customElement: true' compile option?

@ -0,0 +1,7 @@
## avoid_inline_class
Avoid 'new class' — instead, declare the class at the top level scope
## avoid_nested_class
Avoid declaring classes below the top level scope

@ -0,0 +1,19 @@
## store_with_rune_name
It looks like you're using the `$%name%` rune, but there is a local binding called `%name%`. Referencing a local variable with a `$` prefix will create a store subscription. Please rename `%name%` to avoid the ambiguity
## non_state_reference
`%name%` is updated, but is not declared with `$state(...)`. Changing its value will not correctly trigger updates
## derived_iife
Use `$derived.by(() => {...})` instead of `$derived((() => {...})())`
## invalid_props_declaration
Component properties are declared using `$props()` in runes mode. Did you forget to call the function?
## invalid_bindable_declaration
Bindable component properties are declared using `$bindable()` in runes mode. Did you forget to call the function?

@ -0,0 +1,7 @@
## static_state_reference
State referenced in its own scope will never update. Did you mean to reference it inside a closure?
## invalid_rest_eachblock_binding
The rest operator (...) will create a new object and binding '%name%' with the original object will not work

@ -99,8 +99,8 @@
"templating"
],
"scripts": {
"build": "rollup -c && pnpm generate:types && node scripts/check-treeshakeability.js",
"dev": "rollup -cw",
"build": "node scripts/process-messages && rollup -c && pnpm generate:types && node scripts/check-treeshakeability.js",
"dev": "node scripts/process-messages && rollup -cw",
"check": "tsc && cd ./tests/types && tsc",
"check:watch": "tsc --watch",
"generate:version": "node ./scripts/generate-version.js",

@ -111,12 +111,20 @@ function transform(name, dest) {
const value = node.value
.split('\n')
.map((line) => {
if (line === ' * MESSAGE') {
return message
.split('\n')
.map((line) => ` * ${line}`)
.join('\n');
}
if (line.includes('PARAMETER')) {
return vars.map((name) => ` * @param {string} ${name}`).join('\n');
}
return line;
})
.filter((x) => x !== '')
.join('\n');
if (value !== node.value) {
@ -168,7 +176,7 @@ function transform(name, dest) {
for (let i = 0; i < parts.length; i += 1) {
const part = parts[i];
if (i % 2 === 0) {
const str = part.replace(/(`|\$)/g, '\\$1');
const str = part.replace(/(`|\${)/g, '\\$1');
quasis.push({
type: 'TemplateElement',
value: { raw: str, cooked: str },
@ -211,3 +219,4 @@ function transform(name, dest) {
}
transform('compile-errors', 'src/compiler/errors.js');
transform('compile-warnings', 'src/compiler/warnings.js');

@ -47,7 +47,6 @@ export class CompileError extends Error {
}
/**
*
* @param {null | number | NodeLike} node
* @param {string} code
* @param {string} message
@ -65,6 +64,7 @@ function e(node, code, message) {
}
/**
* MESSAGE
* @param {null | number | NodeLike} node
* @param {string} PARAMETER
* @returns {never}

@ -0,0 +1,52 @@
import { getLocator } from 'locate-character';
/** @typedef {{ start?: number, end?: number }} NodeLike */
/** @type {import('#compiler').Warning[]} */
let warnings = [];
/** @type {string | undefined} */
let filename;
let locator = getLocator('', { offsetLine: 1 });
/**
* @param {{
* source: string;
* filename: string | undefined;
* }} options
* @returns {import('#compiler').Warning[]}
*/
export function reset_warnings(options) {
filename = options.filename;
locator = getLocator(options.source, { offsetLine: 1 });
return (warnings = []);
}
/**
* @param {null | NodeLike} node
* @param {string} code
* @param {string} message
*/
function w(node, code, message) {
// @ts-expect-error
if (node.ignores?.has(code)) return;
warnings.push({
code,
message,
filename,
start: node?.start !== undefined ? locator(node.start) : undefined,
end: node?.end !== undefined ? locator(node.end) : undefined
});
}
/**
* MESSAGE
* @param {null | NodeLike} node
* @param {string} PARAMETER
*/
export function CODE(node, PARAMETER) {
w(node, 'CODE', MESSAGE);
}

File diff suppressed because it is too large Load Diff

@ -8,6 +8,7 @@ import { remove_typescript_nodes } from './phases/1-parse/remove_typescript_node
import { analyze_component, analyze_module } from './phases/2-analyze/index.js';
import { transform_component, transform_module } from './phases/3-transform/index.js';
import { validate_component_options, validate_module_options } from './validate-options.js';
import { reset_warnings } from './warnings.js';
export { default as preprocess } from './preprocess/index.js';
/**
@ -20,6 +21,7 @@ export { default as preprocess } from './preprocess/index.js';
*/
export function compile(source, options) {
try {
const warnings = reset_warnings({ source, filename: options.filename });
const validated = validate_component_options(options, '');
let parsed = _parse(source);
@ -44,6 +46,7 @@ export function compile(source, options) {
const analysis = analyze_component(parsed, source, combined_options);
const result = transform_component(analysis, source, combined_options);
result.warnings = warnings;
result.ast = to_public_ast(source, parsed, options.modernAst);
return result;
} catch (e) {
@ -65,9 +68,12 @@ export function compile(source, options) {
*/
export function compileModule(source, options) {
try {
const warnings = reset_warnings({ source, filename: options.filename });
const validated = validate_module_options(options, '');
const analysis = analyze_module(parse_acorn(source, false), validated);
return transform_module(analysis, source, validated);
const result = transform_module(analysis, source, validated);
result.warnings = warnings;
return result;
} catch (e) {
if (e instanceof CompileError) {
handle_compile_error(e, options.filename, source);

@ -7,11 +7,12 @@ import {
regex_starts_with_vowel,
regex_whitespaces
} from '../patterns.js';
import { warn } from '../../warnings.js';
import * as w from '../../warnings.js';
import fuzzymatch from '../1-parse/utils/fuzzymatch.js';
import { is_event_attribute, is_text_attribute } from '../../utils/ast.js';
import { ContentEditableBindings } from '../constants.js';
import { walk } from 'zimmerframe';
import { list } from '../../utils/string.js';
const aria_roles = roles_map.keys();
const abstract_roles = aria_roles.filter((role) => roles_map.get(role)?.abstract);
@ -593,40 +594,53 @@ function is_parent(parent, elements) {
}
/**
* @param {import('#compiler').Attribute} attribute
* @param {import('aria-query').ARIAProperty} name
* @param {import('aria-query').ARIAPropertyDefinition} schema
* @param {string | boolean} value
* @returns {boolean}
* @param {string | true | null} value
*/
function is_valid_aria_attribute_value(schema, value) {
switch (schema.type) {
case 'boolean':
return typeof value === 'boolean';
case 'string':
case 'id':
return typeof value === 'string';
case 'tristate':
return typeof value === 'boolean' || value === 'mixed';
case 'integer':
case 'number':
return typeof value !== 'boolean' && isNaN(Number(value)) === false;
case 'token': // single token
return (
(schema.values || []).indexOf(typeof value === 'string' ? value.toLowerCase() : value) > -1
);
case 'idlist': // if list of ids, split each
return (
typeof value === 'string' &&
value.split(regex_whitespaces).every((id) => typeof id === 'string')
function validate_aria_attribute_value(attribute, name, schema, value) {
const type = schema.type;
const is_string = typeof value === 'string';
if (value === null) return;
if (value === true) value = 'true'; // TODO this is actually incorrect, and we should fix it
if (type === 'boolean' && value !== 'true' && value !== 'false') {
w.a11y_incorrect_aria_attribute_type_boolean(attribute, name);
} else if (type === 'integer' && !Number.isInteger(+value)) {
w.a11y_incorrect_aria_attribute_type_integer(attribute, name);
} else if (type === 'number' && isNaN(+value)) {
w.a11y_incorrect_aria_attribute_type(attribute, name, 'number');
} else if ((type === 'string' || type === 'id') && !is_string) {
w.a11y_incorrect_aria_attribute_type(attribute, name, 'string');
} else if (type === 'idlist' && !is_string) {
w.a11y_incorrect_aria_attribute_type_idlist(attribute, name);
} else if (type === 'token') {
const values = (schema.values ?? []).map((value) => value.toString());
if (!values.includes(value.toLowerCase())) {
w.a11y_incorrect_aria_attribute_type_token(
attribute,
name,
list(values.map((v) => `"${v}"`))
);
case 'tokenlist': // if list of tokens, split each
return (
typeof value === 'string' &&
value
.split(regex_whitespaces)
.every((token) => (schema.values || []).indexOf(token.toLowerCase()) > -1)
}
} else if (type === 'tokenlist') {
const values = (schema.values ?? []).map((value) => value.toString());
if (
value
.toLowerCase()
.split(regex_whitespaces)
.some((value) => !values.includes(value))
) {
w.a11y_incorrect_aria_attribute_type_tokenlist(
attribute,
name,
list(values.map((v) => `"${v}"`))
);
default:
return false;
}
} else if (type === 'tristate' && value !== 'true' && value !== 'false' && value !== 'mixed') {
w.a11y_incorrect_aria_attribute_type_tristate(attribute, name);
}
}
@ -642,7 +656,8 @@ function warn_missing_attribute(node, attributes, name = node.name) {
attributes.length > 1
? attributes.slice(0, -1).join(', ') + ` or ${attributes[attributes.length - 1]}`
: attributes[0];
return /** @type {const} */ ([node, 'a11y-missing-attribute', name, article, sequence]);
w.a11y_missing_attribute(node, name, article, sequence);
}
/**
@ -672,15 +687,6 @@ function check_element(node, state) {
// foreign namespace means elements can have completely different meanings, therefore we don't check them
if (state.options.namespace === 'foreign') return;
/**
* @template {keyof import('../../warnings.js').AllWarnings} T
* @param {{ start?: number, end?: number }} node
* @param {T} code
* @param {Parameters<import('../../warnings.js').AllWarnings[T]>} args
* @returns {void}
*/
const push_warning = (node, code, ...args) => warn(state.analysis.warnings, node, code, ...args);
/** @type {Map<string, import('#compiler').Attribute>} */
const attribute_map = new Map();
@ -727,28 +733,35 @@ function check_element(node, state) {
if (name.startsWith('aria-')) {
if (invisible_elements.includes(node.name)) {
// aria-unsupported-elements
push_warning(attribute, 'a11y-aria-attributes', node.name);
w.a11y_aria_attributes(attribute, node.name);
}
const type = name.slice(5);
if (!aria_attributes.includes(type)) {
const match = fuzzymatch(type, aria_attributes);
push_warning(attribute, 'a11y-unknown-aria-attribute', type, match);
if (match) {
// TODO allow 'overloads' in messages, so that we can use the same code with and without suggestions
w.a11y_unknown_aria_attribute_suggestion(attribute, type, match);
} else {
w.a11y_unknown_aria_attribute(attribute, type);
}
}
if (name === 'aria-hidden' && regex_heading_tags.test(node.name)) {
push_warning(attribute, 'a11y-hidden', node.name);
w.a11y_hidden(attribute, node.name);
}
// aria-proptypes
let value = get_static_value(attribute);
if (value === 'true') value = true;
if (value === 'false') value = false;
if (value !== null && value !== undefined) {
const schema = aria.get(/** @type {import('aria-query').ARIAProperty} */ (name));
if (schema !== undefined && !is_valid_aria_attribute_value(schema, value)) {
push_warning(attribute, 'a11y-incorrect-aria-attribute-type', schema, name);
}
const schema = aria.get(/** @type {import('aria-query').ARIAProperty} */ (name));
if (schema !== undefined) {
validate_aria_attribute_value(
attribute,
/** @type {import('aria-query').ARIAProperty} */ (name),
schema,
value
);
}
// aria-activedescendant-has-tabindex
@ -758,7 +771,7 @@ function check_element(node, state) {
!is_interactive_element(node.name, attribute_map) &&
!attribute_map.has('tabindex')
) {
push_warning(attribute, 'a11y-aria-activedescendant-has-tabindex');
w.a11y_aria_activedescendant_has_tabindex(attribute);
}
}
@ -766,7 +779,7 @@ function check_element(node, state) {
if (name === 'role') {
if (invisible_elements.includes(node.name)) {
// aria-unsupported-elements
push_warning(attribute, 'a11y-misplaced-role', node.name);
w.a11y_misplaced_role(attribute, node.name);
}
const value = get_static_value(attribute);
@ -776,10 +789,14 @@ function check_element(node, state) {
/** @type {import('aria-query').ARIARoleDefinitionKey} current_role */ (c_r);
if (current_role && is_abstract_role(current_role)) {
push_warning(attribute, 'a11y-no-abstract-role', current_role);
w.a11y_no_abstract_role(attribute, current_role);
} else if (current_role && !aria_roles.includes(current_role)) {
const match = fuzzymatch(current_role, aria_roles);
push_warning(attribute, 'a11y-unknown-role', current_role, match);
if (match) {
w.a11y_unknown_role_suggestion(attribute, current_role, match);
} else {
w.a11y_unknown_role(attribute, current_role);
}
}
// no-redundant-roles
@ -788,7 +805,7 @@ function check_element(node, state) {
// <ul role="list"> is ok because CSS list-style:none removes the semantics and this is a way to bring them back
!['ul', 'ol', 'li'].includes(node.name)
) {
push_warning(attribute, 'a11y-no-redundant-roles', current_role);
w.a11y_no_redundant_roles(attribute, current_role);
}
// Footers and headers are special cases, and should not have redundant roles unless they are the children of sections or articles.
@ -797,7 +814,7 @@ function check_element(node, state) {
const has_nested_redundant_role =
current_role === a11y_nested_implicit_semantics.get(node.name);
if (has_nested_redundant_role) {
push_warning(attribute, 'a11y-no-redundant-roles', current_role);
w.a11y_no_redundant_roles(attribute, current_role);
}
}
@ -813,11 +830,13 @@ function check_element(node, state) {
(prop) => !attributes.find((a) => a.name === prop)
);
if (has_missing_props) {
push_warning(
w.a11y_role_has_required_aria_props(
attribute,
'a11y-role-has-required-aria-props',
current_role,
required_role_props
list(
required_role_props.map((v) => `"${v}"`),
'and'
)
);
}
}
@ -836,7 +855,7 @@ function check_element(node, state) {
a11y_interactive_handlers.includes(handler)
);
if (has_interactive_handlers) {
push_warning(node, 'a11y-interactive-supports-focus', current_role);
w.a11y_interactive_supports_focus(node, current_role);
}
}
@ -845,12 +864,7 @@ function check_element(node, state) {
is_interactive_element(node.name, attribute_map) &&
(is_non_interactive_roles(current_role) || is_presentation_role(current_role))
) {
push_warning(
node,
'a11y-no-interactive-element-to-noninteractive-role',
current_role,
node.name
);
w.a11y_no_interactive_element_to_noninteractive_role(node, node.name, current_role);
}
// no-noninteractive-element-to-interactive-role
@ -861,12 +875,7 @@ function check_element(node, state) {
current_role
)
) {
push_warning(
node,
'a11y-no-noninteractive-element-to-interactive-role',
current_role,
node.name
);
w.a11y_no_noninteractive_element_to_interactive_role(node, node.name, current_role);
}
}
}
@ -874,17 +883,17 @@ function check_element(node, state) {
// no-access-key
if (name === 'accesskey') {
push_warning(attribute, 'a11y-accesskey');
w.a11y_accesskey(attribute);
}
// no-autofocus
if (name === 'autofocus') {
push_warning(attribute, 'a11y-autofocus');
w.a11y_autofocus(attribute);
}
// scope
if (name === 'scope' && !is_dynamic_element && node.name !== 'th') {
push_warning(attribute, 'a11y-misplaced-scope');
w.a11y_misplaced_scope(attribute);
}
// tabindex-no-positive
@ -892,7 +901,7 @@ function check_element(node, state) {
const value = get_static_value(attribute);
// @ts-ignore todo is tabindex=true correct case?
if (!isNaN(value) && +value > 0) {
push_warning(attribute, 'a11y-positive-tabindex');
w.a11y_positive_tabindex(attribute);
}
}
}
@ -916,7 +925,7 @@ function check_element(node, state) {
const has_key_event =
handlers.has('keydown') || handlers.has('keyup') || handlers.has('keypress');
if (!has_key_event) {
push_warning(node, 'a11y-click-events-have-key-events');
w.a11y_click_events_have_key_events(node);
}
}
}
@ -934,7 +943,7 @@ function check_element(node, state) {
const tab_index = attribute_map.get('tabindex');
const tab_index_value = get_static_text_value(tab_index);
if (tab_index && (tab_index_value === null || Number(tab_index_value) >= 0)) {
push_warning(node, 'a11y-no-noninteractive-tabindex');
w.a11y_no_noninteractive_tabindex(node);
}
}
@ -949,14 +958,11 @@ function check_element(node, state) {
if (
invalid_aria_props.includes(/** @type {import('aria-query').ARIAProperty} */ (attr.name))
) {
push_warning(
attr,
'a11y-role-supports-aria-props',
attr.name,
role_value,
is_implicit,
node.name
);
if (is_implicit) {
w.a11y_role_supports_aria_props_implicit(attr, attr.name, role_value, node.name);
} else {
w.a11y_role_supports_aria_props(attr, attr.name, role_value);
}
}
}
}
@ -974,7 +980,7 @@ function check_element(node, state) {
a11y_recommended_interactive_handlers.includes(handler)
);
if (has_interactive_handlers) {
push_warning(node, 'a11y-no-noninteractive-element-interactions', node.name);
w.a11y_no_noninteractive_element_interactions(node, node.name);
}
}
@ -993,16 +999,16 @@ function check_element(node, state) {
a11y_interactive_handlers.includes(handler)
);
if (interactive_handlers.length > 0) {
push_warning(node, 'a11y-no-static-element-interactions', node.name, interactive_handlers);
w.a11y_no_static_element_interactions(node, node.name, list(interactive_handlers));
}
}
if (handlers.has('mouseover') && !handlers.has('focus')) {
push_warning(node, 'a11y-mouse-events-have-key-events', 'mouseover', 'focus');
w.a11y_mouse_events_have_key_events(node, 'mouseover', 'focus');
}
if (handlers.has('mouseout') && !handlers.has('blur')) {
push_warning(node, 'a11y-mouse-events-have-key-events', 'mouseout', 'blur');
w.a11y_mouse_events_have_key_events(node, 'mouseout', 'blur');
}
// element-specific checks
@ -1021,14 +1027,14 @@ function check_element(node, state) {
const href_value = get_static_text_value(href);
if (href_value !== null) {
if (href_value === '' || href_value === '#' || /^\W*javascript:/i.test(href_value)) {
push_warning(href, 'a11y-invalid-attribute', href.name, href_value);
w.a11y_invalid_attribute(href, href_value, href.name);
}
}
} else if (!has_spread) {
const id_attribute = get_static_value(attribute_map.get('id'));
const name_attribute = get_static_value(attribute_map.get('name'));
if (!id_attribute && !name_attribute) {
push_warning(...warn_missing_attribute(node, ['href']));
warn_missing_attribute(node, ['href']);
}
}
} else if (!has_spread) {
@ -1036,7 +1042,7 @@ function check_element(node, state) {
if (required_attributes) {
const has_attribute = required_attributes.some((name) => attribute_map.has(name));
if (!has_attribute) {
push_warning(...warn_missing_attribute(node, required_attributes));
warn_missing_attribute(node, required_attributes);
}
}
}
@ -1048,7 +1054,7 @@ function check_element(node, state) {
const required_attributes = ['alt', 'aria-label', 'aria-labelledby'];
const has_attribute = required_attributes.some((name) => attribute_map.has(name));
if (!has_attribute) {
push_warning(...warn_missing_attribute(node, required_attributes, 'input type="image"'));
warn_missing_attribute(node, required_attributes, 'input type="image"');
}
}
// autocomplete-valid
@ -1056,7 +1062,11 @@ function check_element(node, state) {
if (type && autocomplete) {
const autocomplete_value = get_static_value(autocomplete);
if (!is_valid_autocomplete(autocomplete_value)) {
push_warning(autocomplete, 'a11y-autocomplete-valid', type_value, autocomplete_value);
w.a11y_autocomplete_valid(
autocomplete,
/** @type {string} */ (autocomplete_value),
type_value ?? '...'
);
}
}
}
@ -1066,7 +1076,7 @@ function check_element(node, state) {
const aria_hidden = get_static_value(attribute_map.get('aria-hidden'));
if (alt_attribute && !aria_hidden) {
if (/\b(image|picture|photo)\b/i.test(alt_attribute)) {
push_warning(node, 'a11y-img-redundant-alt');
w.a11y_img_redundant_alt(node);
}
}
}
@ -1096,7 +1106,7 @@ function check_element(node, state) {
return has;
};
if (!attribute_map.has('for') && !has_input_child(node)) {
push_warning(node, 'a11y-label-has-associated-control');
w.a11y_label_has_associated_control(node);
}
}
@ -1118,13 +1128,13 @@ function check_element(node, state) {
);
}
if (!has_caption) {
push_warning(node, 'a11y-media-has-caption');
w.a11y_media_has_caption(node);
}
}
if (node.name === 'figcaption') {
if (!is_parent(node.parent, ['figure'])) {
push_warning(node, 'a11y-structure', true);
w.a11y_figcaption_parent(node);
}
}
@ -1138,13 +1148,13 @@ function check_element(node, state) {
(child) => child.type === 'RegularElement' && child.name === 'figcaption'
);
if (index !== -1 && index !== 0 && index !== children.length - 1) {
push_warning(children[index], 'a11y-structure', false);
w.a11y_figcaption_index(children[index]);
}
}
if (a11y_distracting_elements.includes(node.name)) {
// no-distracting-elements
push_warning(node, 'a11y-distracting-elements', node.name);
w.a11y_distracting_elements(node, node.name);
}
// Check content
@ -1154,7 +1164,7 @@ function check_element(node, state) {
a11y_required_content.includes(node.name) &&
node.fragment.nodes.length === 0
) {
push_warning(node, 'a11y-missing-content', node.name);
w.a11y_missing_content(node, node.name);
}
}

@ -1,16 +1,15 @@
import { walk } from 'zimmerframe';
import { warn } from '../../../warnings.js';
import * as w from '../../../warnings.js';
import { is_keyframes_node } from '../../css.js';
/**
* @param {import('#compiler').Css.StyleSheet} stylesheet
* @param {import('../../types.js').RawWarning[]} warnings
*/
export function warn_unused(stylesheet, warnings) {
walk(stylesheet, { warnings, stylesheet }, visitors);
export function warn_unused(stylesheet) {
walk(stylesheet, { stylesheet }, visitors);
}
/** @type {import('zimmerframe').Visitors<import('#compiler').Css.Node, { warnings: import('../../types.js').RawWarning[], stylesheet: import('#compiler').Css.StyleSheet }>} */
/** @type {import('zimmerframe').Visitors<import('#compiler').Css.Node, { stylesheet: import('#compiler').Css.StyleSheet }>} */
const visitors = {
Atrule(node, context) {
if (!is_keyframes_node(node)) {
@ -26,7 +25,7 @@ const visitors = {
if (!node.metadata.used) {
const content = context.state.stylesheet.content;
const text = content.styles.substring(node.start - content.start, node.end - content.start);
warn(context.state.warnings, node, 'css-unused-selector', text);
w.css_unused_selector(node, text);
}
context.next();

@ -1,6 +1,7 @@
import is_reference from 'is-reference';
import { walk } from 'zimmerframe';
import * as e from '../../errors.js';
import * as w from '../../warnings.js';
import {
extract_identifiers,
extract_all_identifiers_from_expression,
@ -14,7 +15,6 @@ import { ReservedKeywords, Runes, SVGElements } from '../constants.js';
import { Scope, ScopeRoot, create_scopes, get_rune, set_scope } from '../scope.js';
import { merge } from '../visitors.js';
import { validation_legacy, validation_runes, validation_runes_js } from './validation.js';
import { warn } from '../../warnings.js';
import check_graph_for_cycles from './utils/check_graph_for_cycles.js';
import { regex_starts_with_newline } from '../patterns.js';
import { create_attribute, is_element_node } from '../nodes.js';
@ -234,16 +234,9 @@ export function analyze_module(ast, options) {
}
}
/** @type {import('../types').RawWarning[]} */
const warnings = [];
const analysis = {
warnings
};
walk(
/** @type {import('estree').Node} */ (ast),
{ scope, analysis },
{ scope },
// @ts-expect-error TODO clean this mess up
merge(set_scope(scopes), validation_runes_js, runes_scope_js_tweaker)
);
@ -251,7 +244,6 @@ export function analyze_module(ast, options) {
return {
module: { ast, scope, scopes },
name: options.filename || 'module',
warnings,
accessors: false,
runes: true,
immutable: true
@ -275,9 +267,6 @@ export function analyze_component(root, source, options) {
/** @type {import('../types.js').Template} */
const template = { ast: root.fragment, scope, scopes };
/** @type {import('../types').RawWarning[]} */
const warnings = [];
// create synthetic bindings for store subscriptions
for (const [name, references] of module.scope.references) {
if (name[0] !== '$' || ReservedKeywords.includes(name)) continue;
@ -331,7 +320,7 @@ export function analyze_component(root, source, options) {
} else if (declaration !== null && Runes.includes(/** @type {any} */ (name))) {
for (const { node, path } of references) {
if (path.at(-1)?.type === 'CallExpression') {
warn(warnings, node, 'store-with-rune-name', store_name);
w.store_with_rune_name(node, store_name);
}
}
}
@ -391,7 +380,6 @@ export function analyze_component(root, source, options) {
reactive_statements: new Map(),
binding_groups: new Map(),
slot_names: new Map(),
warnings,
css: {
ast: root.css,
hash: root.css
@ -408,7 +396,7 @@ export function analyze_component(root, source, options) {
};
if (!options.customElement && root.options?.customElement) {
warn(analysis.warnings, root.options, 'missing-custom-element-compile-option');
w.missing_custom_element_compile_option(root.options);
}
if (analysis.runes) {
@ -498,7 +486,7 @@ export function analyze_component(root, source, options) {
(r) => r.node !== binding.node && r.path.at(-1)?.type !== 'ExportSpecifier'
);
if (!references.length && !instance.scope.declarations.has(`$${name}`)) {
warn(warnings, binding.node, 'unused-export-let', name);
w.unused_export_let(binding.node, name);
}
}
}
@ -538,7 +526,7 @@ export function analyze_component(root, source, options) {
type === 'AwaitBlock' ||
type === 'KeyBlock'
) {
warn(warnings, binding.node, 'non-state-reference', name);
w.non_state_reference(binding.node, name);
continue outer;
}
}
@ -546,7 +534,7 @@ export function analyze_component(root, source, options) {
}
}
warn(warnings, binding.node, 'non-state-reference', name);
w.non_state_reference(binding.node, name);
continue outer;
}
}
@ -563,9 +551,9 @@ export function analyze_component(root, source, options) {
if (
!analysis.css.ast.content.comment ||
!extract_svelte_ignore(analysis.css.ast.content.comment.data).includes('css-unused-selector')
!extract_svelte_ignore(analysis.css.ast.content.comment.data).includes('css_unused_selector')
) {
warn_unused(analysis.css.ast, analysis.warnings);
warn_unused(analysis.css.ast);
}
outer: for (const element of analysis.elements) {
@ -688,7 +676,7 @@ const legacy_scope_tweaker = {
(d) => d.scope === state.analysis.module.scope && d.declaration_kind !== 'const'
)
) {
warn(state.analysis.warnings, node, 'module-script-reactive-declaration');
w.module_script_reactive_declaration(node);
}
if (
@ -874,7 +862,7 @@ const legacy_scope_tweaker = {
}
};
/** @type {import('zimmerframe').Visitors<import('#compiler').SvelteNode, { scope: Scope, analysis: { warnings: import('../types').RawWarning[] } }>} */
/** @type {import('zimmerframe').Visitors<import('#compiler').SvelteNode, { scope: Scope }>} */
const runes_scope_js_tweaker = {
VariableDeclarator(node, { state }) {
if (node.init?.type !== 'CallExpression') return;
@ -1210,7 +1198,7 @@ const common_visitors = {
binding.kind === 'derived') &&
context.state.function_depth === binding.scope.function_depth
) {
warn(context.state.analysis.warnings, node, 'static-state-reference');
w.static_state_reference(node);
}
}
},

@ -12,7 +12,7 @@ import {
object,
unwrap_optional
} from '../../utils/ast.js';
import { warn } from '../../warnings.js';
import * as w from '../../warnings.js';
import fuzzymatch from '../1-parse/utils/fuzzymatch.js';
import { binding_properties } from '../bindings.js';
import {
@ -67,7 +67,7 @@ function validate_component(node, context) {
}
}
validate_attribute_name(attribute, context);
validate_attribute_name(attribute);
if (attribute.name === 'slot') {
validate_slot_attribute(context, attribute);
@ -131,12 +131,7 @@ function validate_element(node, context) {
value.name === attribute.name &&
!context.state.scope.get(value.name)
) {
warn(
context.state.analysis.warnings,
attribute,
'global-event-reference',
attribute.name
);
w.global_event_reference(attribute, attribute.name);
}
}
@ -146,21 +141,15 @@ function validate_element(node, context) {
}
if (attribute.name === 'is' && context.state.options.namespace !== 'foreign') {
warn(context.state.analysis.warnings, attribute, 'avoid-is');
w.avoid_is(attribute);
}
const correct_name = react_attributes.get(attribute.name);
if (correct_name) {
warn(
context.state.analysis.warnings,
attribute,
'invalid-html-attribute',
attribute.name,
correct_name
);
w.invalid_html_attribute(attribute, attribute.name, correct_name);
}
validate_attribute_name(attribute, context);
validate_attribute_name(attribute);
} else if (attribute.type === 'AnimateDirective') {
const parent = context.path.at(-2);
if (parent?.type !== 'EachBlock') {
@ -224,16 +213,15 @@ function validate_element(node, context) {
/**
* @param {import('#compiler').Attribute} attribute
* @param {import('zimmerframe').Context<import('#compiler').SvelteNode, import('./types.js').AnalysisState>} context
*/
function validate_attribute_name(attribute, context) {
function validate_attribute_name(attribute) {
if (
attribute.name.includes(':') &&
!attribute.name.startsWith('xmlns:') &&
!attribute.name.startsWith('xlink:') &&
!attribute.name.startsWith('xml:')
) {
warn(context.state.analysis.warnings, attribute, 'illegal-attribute-character');
w.illegal_attribute_character(attribute);
}
}
@ -311,7 +299,7 @@ function validate_block_not_empty(node, context) {
// Assumption: If the block has zero elements, someone's in the middle of typing it out,
// so don't warn in that case because it would be distracting.
if (node.nodes.length === 1 && node.nodes[0].type === 'Text' && !node.nodes[0].raw.trim()) {
warn(context.state.analysis.warnings, node.nodes[0], 'empty-block');
w.empty_block(node.nodes[0]);
}
}
@ -372,12 +360,7 @@ const validation = {
}
if (binding?.kind === 'each' && binding.metadata?.inside_rest) {
warn(
context.state.analysis.warnings,
binding.node,
'invalid-rest-eachblock-binding',
binding.node.name
);
w.invalid_rest_eachblock_binding(binding.node, binding.node.name);
}
const parent = context.path.at(-1);
@ -531,7 +514,7 @@ const validation = {
binding.declaration_kind === 'import' &&
binding.references.length === 0
) {
warn(context.state.analysis.warnings, node, 'component-name-lowercase', node.name);
w.component_name_lowercase(node, node.name);
}
validate_element(node, context);
@ -570,7 +553,7 @@ const validation = {
!VoidElements.includes(node.name) &&
!SVGElements.includes(node.name)
) {
warn(context.state.analysis.warnings, node, 'invalid-self-closing-tag', node.name);
w.invalid_self_closing_tag(node, node.name);
}
context.next({
@ -766,7 +749,7 @@ export const validation_legacy = merge(validation, a11y_validators, {
(state.ast_type !== 'instance' ||
/** @type {import('#compiler').SvelteNode} */ (path.at(-1)).type !== 'Program')
) {
warn(state.analysis.warnings, node, 'no-reactive-declaration');
w.no_reactive_declaration(node);
}
},
UpdateExpression(node, { state }) {
@ -969,12 +952,12 @@ export const validation_runes_js = {
const allowed_depth = context.state.ast_type === 'module' ? 0 : 1;
if (context.state.scope.function_depth > allowed_depth) {
warn(context.state.analysis.warnings, node, 'avoid-nested-class');
w.avoid_nested_class(node);
}
},
NewExpression(node, context) {
if (node.callee.type === 'ClassExpression' && context.state.scope.function_depth > 0) {
warn(context.state.analysis.warnings, node, 'avoid-inline-class');
w.avoid_inline_class(node);
}
}
};
@ -1127,7 +1110,7 @@ export const validation_runes = merge(validation, a11y_validators, {
if (rune === null) {
if (init?.type === 'Identifier' && init.name === '$props' && !state.scope.get('props')) {
warn(state.analysis.warnings, node, 'invalid-props-declaration');
w.invalid_props_declaration(node);
}
return;
}
@ -1180,7 +1163,7 @@ export const validation_runes = merge(validation, a11y_validators, {
arg.type === 'CallExpression' &&
(arg.callee.type === 'ArrowFunctionExpression' || arg.callee.type === 'FunctionExpression')
) {
warn(state.analysis.warnings, node, 'derived-iife');
w.derived_iife(node);
}
}
},
@ -1190,19 +1173,19 @@ export const validation_runes = merge(validation, a11y_validators, {
node.right.name === '$bindable' &&
!state.scope.get('bindable')
) {
warn(state.analysis.warnings, node, 'invalid-bindable-declaration');
w.invalid_bindable_declaration(node);
}
},
SlotElement(node, { state }) {
if (!state.analysis.custom_element) {
warn(state.analysis.warnings, node, 'deprecated-slot-element');
w.deprecated_slot_element(node);
}
},
OnDirective(node, { state, path }) {
OnDirective(node, { path }) {
const parent_type = path.at(-1)?.type;
// Don't warn on component events; these might not be under the author's control so the warning would be unactionable
if (parent_type === 'RegularElement' || parent_type === 'SvelteElement') {
warn(state.analysis.warnings, node, 'deprecated-event-handler', node.name);
w.deprecated_event_handler(node, node.name);
}
},
// TODO this is a code smell. need to refactor this stuff

@ -17,7 +17,7 @@ export function transform_component(analysis, source, options) {
return {
js: /** @type {any} */ (null),
css: null,
warnings: transform_warnings(source, options.filename, analysis.warnings),
warnings: /** @type {any} */ (null), // set afterwards
metadata: {
runes: analysis.runes
},
@ -60,7 +60,7 @@ export function transform_component(analysis, source, options) {
return {
js,
css,
warnings: transform_warnings(source, options.filename, analysis.warnings), // TODO apply preprocessor sourcemap
warnings: /** @type {any} */ (null), // set afterwards. TODO apply preprocessor sourcemap
metadata: {
runes: analysis.runes
},
@ -79,7 +79,7 @@ export function transform_module(analysis, source, options) {
return {
js: /** @type {any} */ (null),
css: null,
warnings: transform_warnings(source, analysis.name, analysis.warnings),
warnings: /** @type {any} */ (null), // set afterwards
metadata: {
runes: true
},
@ -105,45 +105,10 @@ export function transform_module(analysis, source, options) {
return {
js: print(program, {}),
css: null,
warnings: transform_warnings(source, analysis.name, analysis.warnings),
metadata: {
runes: true
},
warnings: /** @type {any} */ (null), // set afterwards
ast: /** @type {any} */ (null) // set afterwards
};
}
/**
* @param {string} source
* @param {string | undefined} name
* @param {import('../types').RawWarning[]} warnings
* @returns {import('#compiler').Warning[]}
*/
function transform_warnings(source, name, warnings) {
if (warnings.length === 0) return [];
const locate = getLocator(source, { offsetLine: 1 });
/** @type {import('#compiler').Warning[]} */
const result = [];
for (const warning of warnings) {
const start =
warning.position &&
/** @type {import('locate-character').Location} */ (locate(warning.position[0]));
const end =
warning.position &&
/** @type {import('locate-character').Location} */ (locate(warning.position[1]));
result.push({
start,
end,
filename: name,
message: warning.message,
code: warning.code
});
}
return result;
}

@ -6,7 +6,8 @@ import type {
SlotElement,
SvelteElement,
SvelteNode,
SvelteOptions
SvelteOptions,
Warning
} from '#compiler';
import type { Identifier, LabeledStatement, Program } from 'estree';
import type { Scope, ScopeRoot } from './scope.js';
@ -28,19 +29,12 @@ export interface ReactiveStatement {
dependencies: Binding[];
}
export interface RawWarning {
code: string;
message: string;
position: [number, number] | undefined;
}
/**
* Analysis common to modules and components
*/
export interface Analysis {
module: Js;
name: string; // TODO should this be filename? it's used in `compileModule` as well as `compile`
warnings: RawWarning[];
runes: boolean;
immutable: boolean;

@ -0,0 +1,9 @@
/**
* @param {string[]} strings
* @param {string} conjunction
*/
export function list(strings, conjunction = 'or') {
if (strings.length === 1) return strings[0];
if (strings.length === 2) return `${strings[0]} ${conjunction} ${strings[1]}`;
return `${strings.slice(0, -1).join(', ')} ${conjunction} ${strings[strings.length - 1]}`;
}

@ -1,294 +1,628 @@
/** @typedef {Record<string, (...args: any[]) => string>} Warnings */
/** @satisfies {Warnings} */
const css = {
/** @param {string} name */
'css-unused-selector': (name) => `Unused CSS selector "${name}"`
};
/** @satisfies {Warnings} */
const attributes = {
'avoid-is': () => 'The "is" attribute is not supported cross-browser and should be avoided',
/** @param {string} name */
'global-event-reference': (name) =>
`You are referencing globalThis.${name}. Did you forget to declare a variable with that name?`,
'illegal-attribute-character': () =>
"Attributes should not contain ':' characters to prevent ambiguity with Svelte directives",
/**
* @param {string} wrong
* @param {string} right
*/
'invalid-html-attribute': (wrong, right) =>
`'${wrong}' is not a valid HTML attribute. Did you mean '${right}'?`
};
/** @satisfies {Warnings} */
const runes = {
/** @param {string} name */
'store-with-rune-name': (name) =>
`It looks like you're using the $${name} rune, but there is a local binding called ${name}. ` +
`Referencing a local variable with a $ prefix will create a store subscription. Please rename ${name} to avoid the ambiguity.`,
/** @param {string} name */
'non-state-reference': (name) =>
`${name} is updated, but is not declared with $state(...). Changing its value will not correctly trigger updates.`,
'derived-iife': () =>
`Use \`$derived.by(() => {...})\` instead of \`$derived((() => {...})());\``,
'invalid-props-declaration': () =>
`Component properties are declared using $props() in runes mode. Did you forget to call the function?`,
'invalid-bindable-declaration': () =>
`Bindable component properties are declared using $bindable() in runes mode. Did you forget to call the function?`
};
/** @satisfies {Warnings} */
const a11y = {
/** @param {string} name */
'a11y-aria-attributes': (name) => `A11y: <${name}> should not have aria-* attributes`,
/**
* @param {string} attribute
* @param {string | null} [suggestion]
*/
'a11y-unknown-aria-attribute': (attribute, suggestion) =>
`A11y: Unknown aria attribute 'aria-${attribute}'` +
(suggestion ? ` (did you mean '${suggestion}'?)` : ''),
/** @param {string} name */
'a11y-hidden': (name) => `A11y: <${name}> element should not be hidden`,
/**
* @param {import('aria-query').ARIAPropertyDefinition} schema
* @param {string} attribute
*/
'a11y-incorrect-aria-attribute-type': (schema, attribute) => {
let message;
switch (schema.type) {
case 'boolean':
message = `The value of '${attribute}' must be exactly one of true or false`;
break;
case 'id':
message = `The value of '${attribute}' must be a string that represents a DOM element ID`;
break;
case 'idlist':
message = `The value of '${attribute}' must be a space-separated list of strings that represent DOM element IDs`;
break;
case 'tristate':
message = `The value of '${attribute}' must be exactly one of true, false, or mixed`;
break;
case 'token':
message = `The value of '${attribute}' must be exactly one of ${(schema.values || []).join(
', '
)}`;
break;
case 'tokenlist':
message = `The value of '${attribute}' must be a space-separated list of one or more of ${(
schema.values || []
).join(', ')}`;
break;
default:
message = `The value of '${attribute}' must be of type ${schema.type}`;
}
return `A11y: ${message}`;
},
'a11y-aria-activedescendant-has-tabindex': () =>
'A11y: Elements with attribute aria-activedescendant should have tabindex value',
/** @param {string} name */
'a11y-misplaced-role': (name) => `A11y: <${name}> should not have role attribute`,
/** @param {string | boolean} role */
'a11y-no-abstract-role': (role) => `A11y: Abstract role '${role}' is forbidden`,
/**
* @param {string | boolean} role
* @param {string | null} [suggestion]
*/
'a11y-unknown-role': (role, suggestion) =>
`A11y: Unknown role '${role}'` + (suggestion ? ` (did you mean '${suggestion}'?)` : ''),
/** @param {string | boolean} role */
'a11y-no-redundant-roles': (role) => `A11y: Redundant role '${role}'`,
/**
* @param {string} role
* @param {string[]} props
*/
'a11y-role-has-required-aria-props': (role, props) =>
`A11y: Elements with the ARIA role "${role}" must have the following attributes defined: ${props
.map((name) => `"${name}"`)
.join(', ')}`,
/** @param {string} role */
'a11y-interactive-supports-focus': (role) =>
`A11y: Elements with the '${role}' interactive role must have a tabindex value.`,
/**
* @param {string | boolean} role
* @param {string} element
*/
'a11y-no-interactive-element-to-noninteractive-role': (role, element) =>
`A11y: <${element}> cannot have role '${role}'`,
/**
* @param {string | boolean} role
* @param {string} element
*/
'a11y-no-noninteractive-element-to-interactive-role': (role, element) =>
`A11y: Non-interactive element <${element}> cannot have interactive role '${role}'`,
'a11y-accesskey': () => 'A11y: Avoid using accesskey',
'a11y-autofocus': () => 'A11y: Avoid using autofocus',
'a11y-misplaced-scope': () => 'A11y: The scope attribute should only be used with <th> elements',
'a11y-positive-tabindex': () => 'A11y: avoid tabindex values above zero',
'a11y-click-events-have-key-events': () =>
'A11y: visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type="button"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.',
'a11y-no-noninteractive-tabindex': () =>
'A11y: noninteractive element cannot have nonnegative tabIndex value',
/**
* @param {string} attribute
* @param {string} role
* @param {boolean} is_implicit
* @param {string} name
*/
'a11y-role-supports-aria-props': (attribute, role, is_implicit, name) => {
let message = `The attribute '${attribute}' is not supported by the role '${role}'.`;
if (is_implicit) {
message += ` This role is implicit on the element <${name}>.`;
}
return `A11y: ${message}`;
},
/** @param {string} element */
'a11y-no-noninteractive-element-interactions': (element) =>
`A11y: Non-interactive element <${element}> should not be assigned mouse or keyboard event listeners.`,
/**
* @param {string} element
* @param {string[]} handlers
*/
'a11y-no-static-element-interactions': (element, handlers) =>
`A11y: <${element}> with ${handlers.join(', ')} ${
handlers.length === 1 ? 'handler' : 'handlers'
} must have an ARIA role`,
/**
* @param {string} href_attribute
* @param {string} href_value
*/
'a11y-invalid-attribute': (href_attribute, href_value) =>
`A11y: '${href_value}' is not a valid ${href_attribute} attribute`,
/**
* @param {string} name
* @param {string} article
* @param {string} sequence
*/
'a11y-missing-attribute': (name, article, sequence) =>
`A11y: <${name}> element should have ${article} ${sequence} attribute`,
/**
* @param {null | true | string} type
* @param {null | true | string} value
*/
'a11y-autocomplete-valid': (type, value) =>
`A11y: The value '${value}' is not supported by the attribute 'autocomplete' on element <input type="${
type || '...'
}">`,
'a11y-img-redundant-alt': () =>
'A11y: Screenreaders already announce <img> elements as an image.',
'a11y-label-has-associated-control': () =>
'A11y: A form label must be associated with a control.',
'a11y-media-has-caption': () => 'A11y: <video> elements must have a <track kind="captions">',
/** @param {string} name */
'a11y-distracting-elements': (name) => `A11y: Avoid <${name}> elements`,
/** @param {boolean} immediate */
'a11y-structure': (immediate) =>
immediate
? 'A11y: <figcaption> must be an immediate child of <figure>'
: 'A11y: <figcaption> must be first or last child of <figure>',
/**
* @param {string} event
* @param {string} accompanied_by
*/
'a11y-mouse-events-have-key-events': (event, accompanied_by) =>
`A11y: '${event}' event must be accompanied by '${accompanied_by}' event`,
/** @param {string} name */
'a11y-missing-content': (name) => `A11y: <${name}> element should have child content`
};
/** @satisfies {Warnings} */
const state = {
'static-state-reference': () =>
`State referenced in its own scope will never update. Did you mean to reference it inside a closure?`,
/** @param {string} name */
'invalid-rest-eachblock-binding': (name) =>
`The rest operator (...) will create a new object and binding '${name}' with the original object will not work`
};
/** @satisfies {Warnings} */
const performance = {
'avoid-inline-class': () =>
`Avoid 'new class' — instead, declare the class at the top level scope`,
'avoid-nested-class': () => `Avoid declaring classes below the top level scope`
};
/** @satisfies {Warnings} */
const components = {
/** @param {string} name */
'component-name-lowercase': (name) =>
`<${name}> will be treated as an HTML element unless it begins with a capital letter`
};
const legacy = {
'no-reactive-declaration': () =>
`Reactive declarations only exist at the top level of the instance script`,
'module-script-reactive-declaration': () =>
'All dependencies of the reactive declaration are declared in a module script and will not be reactive',
/** @param {string} name */
'unused-export-let': (name) =>
`Component has unused export property '${name}'. If it is for external reference only, please consider using \`export const ${name}\``,
'deprecated-slot-element': () =>
`Using <slot> to render parent content is deprecated. Use {@render ...} tags instead.`,
/** @param {string} name */
'deprecated-event-handler': (name) =>
`Using on:${name} to listen to the ${name} event is is deprecated. Use the event attribute on${name} instead.`
};
const block = {
'empty-block': () => 'Empty block'
};
const options = {
'missing-custom-element-compile-option': () =>
"The 'customElement' option is used when generating a custom element. Did you forget the 'customElement: true' compile option?"
};
const misc = {
/** @param {string} name */
'invalid-self-closing-tag': (name) =>
`Self-closing HTML tags for non-void elements are ambiguous — use <${name} ...></${name}> rather than <${name} ... />`
};
/** @satisfies {Warnings} */
const warnings = {
...css,
...attributes,
...runes,
...a11y,
...performance,
...state,
...components,
...legacy,
...block,
...options,
...misc
};
/** @typedef {typeof warnings} AllWarnings */
/**
* @template {keyof AllWarnings} T
* @param {import('./phases/types').RawWarning[]} array the array to push the warning to, if not ignored
* @param {{ start?: number, end?: number, type?: string, parent?: import('#compiler').SvelteNode | null, leadingComments?: import('estree').Comment[] } | null} node the node related to the warning
* @param {T} code the warning code
* @param {Parameters<AllWarnings[T]>} args the arguments to pass to the warning function
* @returns {void}
*/
export function warn(array, node, code, ...args) {
// @ts-expect-error
if (node.ignores?.has(code)) return;
/* This file is generated by scripts/process-messages.js. Do not edit! */
import { getLocator } from 'locate-character';
const fn = warnings[code];
/** @typedef {{ start?: number, end?: number }} NodeLike */
/** @type {import('#compiler').Warning[]} */
let warnings = [];
/** @type {string | undefined} */
let filename;
let locator = getLocator('', { offsetLine: 1 });
const start = node?.start;
const end = node?.end;
/**
* @param {{
* source: string;
* filename: string | undefined;
* }} options
* @returns {import('#compiler').Warning[]}
*/
export function reset_warnings(options) {
filename = options.filename;
locator = getLocator(options.source, { offsetLine: 1 });
return warnings = [];
}
/**
* @param {null | NodeLike} node
* @param {string} code
* @param {string} message
*/
function w(node, code, message) {
// @ts-expect-error
if (node.ignores?.has(code)) return;
array.push({
warnings.push({
code,
// @ts-expect-error
message: fn(...args),
position: start !== undefined && end !== undefined ? [start, end] : undefined
message,
filename,
start: node?.start !== undefined ? locator(node.start) : undefined,
end: node?.end !== undefined ? locator(node.end) : undefined
});
}
/**
* <%name%> should not have aria-* attributes
* @param {null | NodeLike} node
* @param {string} name
*/
export function a11y_aria_attributes(node, name) {
w(node, "a11y_aria_attributes", `<${name}> should not have aria-* attributes`);
}
/**
* Unknown aria attribute 'aria-%attribute%'
* @param {null | NodeLike} node
* @param {string} attribute
*/
export function a11y_unknown_aria_attribute(node, attribute) {
w(node, "a11y_unknown_aria_attribute", `Unknown aria attribute 'aria-${attribute}'`);
}
/**
* Unknown aria attribute 'aria-%attribute%'. Did you mean '%suggestion%'?
* @param {null | NodeLike} node
* @param {string} attribute
* @param {string} suggestion
*/
export function a11y_unknown_aria_attribute_suggestion(node, attribute, suggestion) {
w(node, "a11y_unknown_aria_attribute_suggestion", `Unknown aria attribute 'aria-${attribute}'. Did you mean '${suggestion}'?`);
}
/**
* <%name%> element should not be hidden
* @param {null | NodeLike} node
* @param {string} name
*/
export function a11y_hidden(node, name) {
w(node, "a11y_hidden", `<${name}> element should not be hidden`);
}
/**
* The value of '%attribute%' must be either 'true' or 'false'
* @param {null | NodeLike} node
* @param {string} attribute
*/
export function a11y_incorrect_aria_attribute_type_boolean(node, attribute) {
w(node, "a11y_incorrect_aria_attribute_type_boolean", `The value of '${attribute}' must be either 'true' or 'false'`);
}
/**
* The value of '%attribute%' must be an integer
* @param {null | NodeLike} node
* @param {string} attribute
*/
export function a11y_incorrect_aria_attribute_type_integer(node, attribute) {
w(node, "a11y_incorrect_aria_attribute_type_integer", `The value of '${attribute}' must be an integer`);
}
/**
* The value of '%attribute%' must be a string that represents a DOM element ID
* @param {null | NodeLike} node
* @param {string} attribute
*/
export function a11y_incorrect_aria_attribute_type_id(node, attribute) {
w(node, "a11y_incorrect_aria_attribute_type_id", `The value of '${attribute}' must be a string that represents a DOM element ID`);
}
/**
* The value of '%attribute%' must be a space-separated list of strings that represent DOM element IDs
* @param {null | NodeLike} node
* @param {string} attribute
*/
export function a11y_incorrect_aria_attribute_type_idlist(node, attribute) {
w(node, "a11y_incorrect_aria_attribute_type_idlist", `The value of '${attribute}' must be a space-separated list of strings that represent DOM element IDs`);
}
/**
* The value of '%attribute%' must be exactly one of true, false, or mixed
* @param {null | NodeLike} node
* @param {string} attribute
*/
export function a11y_incorrect_aria_attribute_type_tristate(node, attribute) {
w(node, "a11y_incorrect_aria_attribute_type_tristate", `The value of '${attribute}' must be exactly one of true, false, or mixed`);
}
/**
* The value of '%attribute%' must be exactly one of %values%
* @param {null | NodeLike} node
* @param {string} attribute
* @param {string} values
*/
export function a11y_incorrect_aria_attribute_type_token(node, attribute, values) {
w(node, "a11y_incorrect_aria_attribute_type_token", `The value of '${attribute}' must be exactly one of ${values}`);
}
/**
* The value of '%attribute%' must be a space-separated list of one or more of %values%
* @param {null | NodeLike} node
* @param {string} attribute
* @param {string} values
*/
export function a11y_incorrect_aria_attribute_type_tokenlist(node, attribute, values) {
w(node, "a11y_incorrect_aria_attribute_type_tokenlist", `The value of '${attribute}' must be a space-separated list of one or more of ${values}`);
}
/**
* The value of '%attribute%' must be of type %type%
* @param {null | NodeLike} node
* @param {string} attribute
* @param {string} type
*/
export function a11y_incorrect_aria_attribute_type(node, attribute, type) {
w(node, "a11y_incorrect_aria_attribute_type", `The value of '${attribute}' must be of type ${type}`);
}
/**
* Elements with attribute aria-activedescendant should have tabindex value
* @param {null | NodeLike} node
*/
export function a11y_aria_activedescendant_has_tabindex(node) {
w(node, "a11y_aria_activedescendant_has_tabindex", "Elements with attribute aria-activedescendant should have tabindex value");
}
/**
* <%name%> should not have role attribute
* @param {null | NodeLike} node
* @param {string} name
*/
export function a11y_misplaced_role(node, name) {
w(node, "a11y_misplaced_role", `<${name}> should not have role attribute`);
}
/**
* Abstract role '%role%' is forbidden
* @param {null | NodeLike} node
* @param {string} role
*/
export function a11y_no_abstract_role(node, role) {
w(node, "a11y_no_abstract_role", `Abstract role '${role}' is forbidden`);
}
/**
* Unknown role '%role%'
* @param {null | NodeLike} node
* @param {string} role
*/
export function a11y_unknown_role(node, role) {
w(node, "a11y_unknown_role", `Unknown role '${role}'`);
}
/**
* Unknown role '%role%'. Did you mean '%suggestion%'?
* @param {null | NodeLike} node
* @param {string} role
* @param {string} suggestion
*/
export function a11y_unknown_role_suggestion(node, role, suggestion) {
w(node, "a11y_unknown_role_suggestion", `Unknown role '${role}'. Did you mean '${suggestion}'?`);
}
/**
* Redundant role '%role%'
* @param {null | NodeLike} node
* @param {string} role
*/
export function a11y_no_redundant_roles(node, role) {
w(node, "a11y_no_redundant_roles", `Redundant role '${role}'`);
}
/**
* Elements with the ARIA role "%role%" must have the following attributes defined: %props%
* @param {null | NodeLike} node
* @param {string} role
* @param {string} props
*/
export function a11y_role_has_required_aria_props(node, role, props) {
w(node, "a11y_role_has_required_aria_props", `Elements with the ARIA role "${role}" must have the following attributes defined: ${props}`);
}
/**
* Elements with the '%role%' interactive role must have a tabindex value.
* @param {null | NodeLike} node
* @param {string} role
*/
export function a11y_interactive_supports_focus(node, role) {
w(node, "a11y_interactive_supports_focus", `Elements with the '${role}' interactive role must have a tabindex value.`);
}
/**
* <%element%> cannot have role '%role%'
* @param {null | NodeLike} node
* @param {string} element
* @param {string} role
*/
export function a11y_no_interactive_element_to_noninteractive_role(node, element, role) {
w(node, "a11y_no_interactive_element_to_noninteractive_role", `<${element}> cannot have role '${role}'`);
}
/**
* Non-interactive element <%element%> cannot have interactive role '%role%'
* @param {null | NodeLike} node
* @param {string} element
* @param {string} role
*/
export function a11y_no_noninteractive_element_to_interactive_role(node, element, role) {
w(node, "a11y_no_noninteractive_element_to_interactive_role", `Non-interactive element <${element}> cannot have interactive role '${role}'`);
}
/**
* Avoid using accesskey
* @param {null | NodeLike} node
*/
export function a11y_accesskey(node) {
w(node, "a11y_accesskey", "Avoid using accesskey");
}
/**
* Avoid using autofocus
* @param {null | NodeLike} node
*/
export function a11y_autofocus(node) {
w(node, "a11y_autofocus", "Avoid using autofocus");
}
/**
* The scope attribute should only be used with <th> elements
* @param {null | NodeLike} node
*/
export function a11y_misplaced_scope(node) {
w(node, "a11y_misplaced_scope", "The scope attribute should only be used with <th> elements");
}
/**
* Avoid tabindex values above zero
* @param {null | NodeLike} node
*/
export function a11y_positive_tabindex(node) {
w(node, "a11y_positive_tabindex", "Avoid tabindex values above zero");
}
/**
* Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type="button"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.
* @param {null | NodeLike} node
*/
export function a11y_click_events_have_key_events(node) {
w(node, "a11y_click_events_have_key_events", "Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type=\"button\"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.");
}
/**
* noninteractive element cannot have nonnegative tabIndex value
* @param {null | NodeLike} node
*/
export function a11y_no_noninteractive_tabindex(node) {
w(node, "a11y_no_noninteractive_tabindex", "noninteractive element cannot have nonnegative tabIndex value");
}
/**
* The attribute '%attribute%' is not supported by the role '%role%'
* @param {null | NodeLike} node
* @param {string} attribute
* @param {string} role
*/
export function a11y_role_supports_aria_props(node, attribute, role) {
w(node, "a11y_role_supports_aria_props", `The attribute '${attribute}' is not supported by the role '${role}'`);
}
/**
* The attribute '%attribute%' is not supported by the role '%role%'. This role is implicit on the element <%name%>
* @param {null | NodeLike} node
* @param {string} attribute
* @param {string} role
* @param {string} name
*/
export function a11y_role_supports_aria_props_implicit(node, attribute, role, name) {
w(node, "a11y_role_supports_aria_props_implicit", `The attribute '${attribute}' is not supported by the role '${role}'. This role is implicit on the element <${name}>`);
}
/**
* Non-interactive element <%element%> should not be assigned mouse or keyboard event listeners.
* @param {null | NodeLike} node
* @param {string} element
*/
export function a11y_no_noninteractive_element_interactions(node, element) {
w(node, "a11y_no_noninteractive_element_interactions", `Non-interactive element <${element}> should not be assigned mouse or keyboard event listeners.`);
}
/**
* <%element%> with a %handler% handler must have an ARIA role
* @param {null | NodeLike} node
* @param {string} element
* @param {string} handler
*/
export function a11y_no_static_element_interactions(node, element, handler) {
w(node, "a11y_no_static_element_interactions", `<${element}> with a ${handler} handler must have an ARIA role`);
}
/**
* '%href_value%' is not a valid %href_attribute% attribute
* @param {null | NodeLike} node
* @param {string} href_value
* @param {string} href_attribute
*/
export function a11y_invalid_attribute(node, href_value, href_attribute) {
w(node, "a11y_invalid_attribute", `'${href_value}' is not a valid ${href_attribute} attribute`);
}
/**
* <%name%> element should have %article% %sequence% attribute
* @param {null | NodeLike} node
* @param {string} name
* @param {string} article
* @param {string} sequence
*/
export function a11y_missing_attribute(node, name, article, sequence) {
w(node, "a11y_missing_attribute", `<${name}> element should have ${article} ${sequence} attribute`);
}
/**
* The value '%value%' is not supported by the attribute 'autocomplete' on element <input type="%type%">
* @param {null | NodeLike} node
* @param {string} value
* @param {string} type
*/
export function a11y_autocomplete_valid(node, value, type) {
w(node, "a11y_autocomplete_valid", `The value '${value}' is not supported by the attribute 'autocomplete' on element <input type="${type}">`);
}
/**
* Screenreaders already announce <img> elements as an image.
* @param {null | NodeLike} node
*/
export function a11y_img_redundant_alt(node) {
w(node, "a11y_img_redundant_alt", "Screenreaders already announce <img> elements as an image.");
}
/**
* A form label must be associated with a control.
* @param {null | NodeLike} node
*/
export function a11y_label_has_associated_control(node) {
w(node, "a11y_label_has_associated_control", "A form label must be associated with a control.");
}
/**
* <video> elements must have a <track kind="captions">
* @param {null | NodeLike} node
*/
export function a11y_media_has_caption(node) {
w(node, "a11y_media_has_caption", "<video> elements must have a <track kind=\"captions\">");
}
/**
* Avoid <%name%> elements
* @param {null | NodeLike} node
* @param {string} name
*/
export function a11y_distracting_elements(node, name) {
w(node, "a11y_distracting_elements", `Avoid <${name}> elements`);
}
/**
* `<figcaption>` must be an immediate child of `<figure>`
* @param {null | NodeLike} node
*/
export function a11y_figcaption_parent(node) {
w(node, "a11y_figcaption_parent", "`<figcaption>` must be an immediate child of `<figure>`");
}
/**
* `<figcaption>` must be first or last child of `<figure>`
* @param {null | NodeLike} node
*/
export function a11y_figcaption_index(node) {
w(node, "a11y_figcaption_index", "`<figcaption>` must be first or last child of `<figure>`");
}
/**
* '%event%' event must be accompanied by '%accompanied_by%' event
* @param {null | NodeLike} node
* @param {string} event
* @param {string} accompanied_by
*/
export function a11y_mouse_events_have_key_events(node, event, accompanied_by) {
w(node, "a11y_mouse_events_have_key_events", `'${event}' event must be accompanied by '${accompanied_by}' event`);
}
/**
* <%name%> element should have child content
* @param {null | NodeLike} node
* @param {string} name
*/
export function a11y_missing_content(node, name) {
w(node, "a11y_missing_content", `<${name}> element should have child content`);
}
/**
* The "is" attribute is not supported cross-browser and should be avoided
* @param {null | NodeLike} node
*/
export function avoid_is(node) {
w(node, "avoid_is", "The \"is\" attribute is not supported cross-browser and should be avoided");
}
/**
* You are referencing globalThis.%name%. Did you forget to declare a variable with that name?
* @param {null | NodeLike} node
* @param {string} name
*/
export function global_event_reference(node, name) {
w(node, "global_event_reference", `You are referencing globalThis.${name}. Did you forget to declare a variable with that name?`);
}
/**
* Attributes should not contain ':' characters to prevent ambiguity with Svelte directives
* @param {null | NodeLike} node
*/
export function illegal_attribute_character(node) {
w(node, "illegal_attribute_character", "Attributes should not contain ':' characters to prevent ambiguity with Svelte directives");
}
/**
* '%wrong%' is not a valid HTML attribute. Did you mean '%right%'?
* @param {null | NodeLike} node
* @param {string} wrong
* @param {string} right
*/
export function invalid_html_attribute(node, wrong, right) {
w(node, "invalid_html_attribute", `'${wrong}' is not a valid HTML attribute. Did you mean '${right}'?`);
}
/**
* Empty block
* @param {null | NodeLike} node
*/
export function empty_block(node) {
w(node, "empty_block", "Empty block");
}
/**
* <%name%> will be treated as an HTML element unless it begins with a capital letter
* @param {null | NodeLike} node
* @param {string} name
*/
export function component_name_lowercase(node, name) {
w(node, "component_name_lowercase", `<${name}> will be treated as an HTML element unless it begins with a capital letter`);
}
/**
* Unused CSS selector "%name%"
* @param {null | NodeLike} node
* @param {string} name
*/
export function css_unused_selector(node, name) {
w(node, "css_unused_selector", `Unused CSS selector "${name}"`);
}
/**
* Reactive declarations only exist at the top level of the instance script
* @param {null | NodeLike} node
*/
export function no_reactive_declaration(node) {
w(node, "no_reactive_declaration", "Reactive declarations only exist at the top level of the instance script");
}
/**
* All dependencies of the reactive declaration are declared in a module script and will not be reactive
* @param {null | NodeLike} node
*/
export function module_script_reactive_declaration(node) {
w(node, "module_script_reactive_declaration", "All dependencies of the reactive declaration are declared in a module script and will not be reactive");
}
/**
* Component has unused export property '%name%'. If it is for external reference only, please consider using `export const %name%`
* @param {null | NodeLike} node
* @param {string} name
*/
export function unused_export_let(node, name) {
w(node, "unused_export_let", `Component has unused export property '${name}'. If it is for external reference only, please consider using \`export const ${name}\``);
}
/**
* Using <slot> to render parent content is deprecated. Use {@render ...} tags instead.
* @param {null | NodeLike} node
*/
export function deprecated_slot_element(node) {
w(node, "deprecated_slot_element", "Using <slot> to render parent content is deprecated. Use {@render ...} tags instead.");
}
/**
* Using on:%name% to listen to the %name% event is is deprecated. Use the event attribute on%name% instead.
* @param {null | NodeLike} node
* @param {string} name
*/
export function deprecated_event_handler(node, name) {
w(node, "deprecated_event_handler", `Using on:${name} to listen to the ${name} event is is deprecated. Use the event attribute on${name} instead.`);
}
/**
* Self-closing HTML tags for non-void elements are ambiguous use <%name% ...></%name%> rather than <%name% ... />
* @param {null | NodeLike} node
* @param {string} name
*/
export function invalid_self_closing_tag(node, name) {
w(node, "invalid_self_closing_tag", `Self-closing HTML tags for non-void elements are ambiguous — use <${name} ...></${name}> rather than <${name} ... />`);
}
/**
* The 'customElement' option is used when generating a custom element. Did you forget the 'customElement: true' compile option?
* @param {null | NodeLike} node
*/
export function missing_custom_element_compile_option(node) {
w(node, "missing_custom_element_compile_option", "The 'customElement' option is used when generating a custom element. Did you forget the 'customElement: true' compile option?");
}
/**
* Avoid 'new class' instead, declare the class at the top level scope
* @param {null | NodeLike} node
*/
export function avoid_inline_class(node) {
w(node, "avoid_inline_class", "Avoid 'new class' — instead, declare the class at the top level scope");
}
/**
* Avoid declaring classes below the top level scope
* @param {null | NodeLike} node
*/
export function avoid_nested_class(node) {
w(node, "avoid_nested_class", "Avoid declaring classes below the top level scope");
}
/**
* It looks like you're using the `$%name%` rune, but there is a local binding called `%name%`. Referencing a local variable with a `$` prefix will create a store subscription. Please rename `%name%` to avoid the ambiguity
* @param {null | NodeLike} node
* @param {string} name
*/
export function store_with_rune_name(node, name) {
w(node, "store_with_rune_name", `It looks like you're using the \`$${name}\` rune, but there is a local binding called \`${name}\`. Referencing a local variable with a \`$\` prefix will create a store subscription. Please rename \`${name}\` to avoid the ambiguity`);
}
/**
* `%name%` is updated, but is not declared with `$state(...)`. Changing its value will not correctly trigger updates
* @param {null | NodeLike} node
* @param {string} name
*/
export function non_state_reference(node, name) {
w(node, "non_state_reference", `\`${name}\` is updated, but is not declared with \`$state(...)\`. Changing its value will not correctly trigger updates`);
}
/**
* Use `$derived.by(() => {...})` instead of `$derived((() => {...})())`
* @param {null | NodeLike} node
*/
export function derived_iife(node) {
w(node, "derived_iife", "Use `$derived.by(() => {...})` instead of `$derived((() => {...})())`");
}
/**
* Component properties are declared using `$props()` in runes mode. Did you forget to call the function?
* @param {null | NodeLike} node
*/
export function invalid_props_declaration(node) {
w(node, "invalid_props_declaration", "Component properties are declared using `$props()` in runes mode. Did you forget to call the function?");
}
/**
* Bindable component properties are declared using `$bindable()` in runes mode. Did you forget to call the function?
* @param {null | NodeLike} node
*/
export function invalid_bindable_declaration(node) {
w(node, "invalid_bindable_declaration", "Bindable component properties are declared using `$bindable()` in runes mode. Did you forget to call the function?");
}
/**
* State referenced in its own scope will never update. Did you mean to reference it inside a closure?
* @param {null | NodeLike} node
*/
export function static_state_reference(node) {
w(node, "static_state_reference", "State referenced in its own scope will never update. Did you mean to reference it inside a closure?");
}
/**
* The rest operator (...) will create a new object and binding '%name%' with the original object will not work
* @param {null | NodeLike} node
* @param {string} name
*/
export function invalid_rest_eachblock_binding(node, name) {
w(node, "invalid_rest_eachblock_binding", `The rest operator (...) will create a new object and binding '${name}' with the original object will not work`);
}

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
end: {
character: 44,
column: 14,

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
end: {
character: 33,
column: 6,

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".unused"',
start: {
character: 79,

@ -4,7 +4,7 @@ export default test({
warnings: [
{
filename: 'SvelteComponent.svelte',
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".x"',
start: {
line: 4,

@ -3,19 +3,19 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".b ~ .c"',
start: { character: 269, column: 1, line: 15 },
end: { character: 276, column: 8, line: 15 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".c ~ .d"',
start: { character: 296, column: 1, line: 16 },
end: { character: 303, column: 8, line: 16 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".b ~ .d"',
start: { character: 323, column: 1, line: 17 },
end: { character: 330, column: 8, line: 17 }

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".e ~ .f"',
start: { character: 812, column: 1, line: 35 },
end: { character: 819, column: 8, line: 35 }

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".b ~ .c"',
start: { character: 198, column: 1, line: 13 },
end: { character: 205, column: 8, line: 13 }

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".b ~ .c"',
start: { character: 319, column: 1, line: 18 },
end: { character: 326, column: 8, line: 18 }

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".b ~ .c"',
start: { character: 215, column: 1, line: 14 },
end: { character: 222, column: 8, line: 14 }

@ -3,19 +3,19 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".b ~ .c"',
start: { character: 269, column: 1, line: 16 },
end: { character: 276, column: 8, line: 16 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".b ~ .d"',
start: { character: 296, column: 1, line: 17 },
end: { character: 303, column: 8, line: 17 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".c ~ .d"',
start: { character: 323, column: 1, line: 18 },
end: { character: 330, column: 8, line: 18 }

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
end: {
character: 479,
column: 19,

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
end: {
character: 472,
column: 19,

@ -3,37 +3,37 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".a ~ .b"',
start: { character: 110, column: 1, line: 10 },
end: { character: 117, column: 8, line: 10 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".b ~ .c"',
start: { character: 137, column: 1, line: 11 },
end: { character: 144, column: 8, line: 11 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".c ~ .f"',
start: { character: 164, column: 1, line: 12 },
end: { character: 171, column: 8, line: 12 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".f ~ .g"',
start: { character: 191, column: 1, line: 13 },
end: { character: 198, column: 8, line: 13 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".b ~ .f"',
start: { character: 218, column: 1, line: 14 },
end: { character: 225, column: 8, line: 14 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".b ~ .g"',
start: { character: 245, column: 1, line: 15 },
end: { character: 252, column: 8, line: 15 }

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".not-match > * ~ *"',
start: { character: 50, column: 1, line: 5 },
end: { character: 68, column: 19, line: 5 }

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
end: {
character: 496,
column: 10,

@ -3,25 +3,25 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector "article ~ div"',
start: { character: 275, column: 1, line: 12 },
end: { character: 288, column: 14, line: 12 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector "span ~ article"',
start: { character: 308, column: 1, line: 13 },
end: { character: 322, column: 15, line: 13 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector "b ~ article"',
start: { character: 342, column: 1, line: 14 },
end: { character: 353, column: 12, line: 14 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector "span ~ div"',
start: { character: 373, column: 1, line: 15 },
end: { character: 383, column: 11, line: 15 }

@ -4,7 +4,7 @@ export default test({
warnings: [
{
filename: 'SvelteComponent.svelte',
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".unused :global"',
start: {
line: 16,

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ":global(.foo) .bar"',
start: { character: 9, column: 1, line: 2 },
end: { character: 27, column: 19, line: 2 }

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ":host > span"',
start: {
character: 145,

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
end: {
character: 38,
column: 11,

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
end: {
character: 239,
column: 13,
@ -17,7 +17,7 @@ export default test({
}
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
end: {
character: 302,
column: 10,
@ -31,7 +31,7 @@ export default test({
}
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
end: {
character: 328,
column: 6,
@ -45,7 +45,7 @@ export default test({
}
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
end: {
character: 381,
column: 10,
@ -59,7 +59,7 @@ export default test({
}
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
end: {
character: 471,
column: 7,
@ -73,7 +73,7 @@ export default test({
}
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
end: {
character: 634,
column: 5,
@ -87,7 +87,7 @@ export default test({
}
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
end: {
character: 666,
column: 9,

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector "div > p"',
start: {
line: 8,

@ -1,4 +1,4 @@
<!-- svelte-ignore a11y-missing-attribute -->
<!-- svelte-ignore a11y_missing_attribute -->
<a>
<b>
<c>
@ -21,4 +21,4 @@
.foo {
color: green;
}
</style>
</style>

@ -3,25 +3,25 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".a + .e"',
start: { character: 242, column: 1, line: 14 },
end: { character: 249, column: 8, line: 14 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".b + .c"',
start: { character: 269, column: 1, line: 15 },
end: { character: 276, column: 8, line: 15 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".c + .d"',
start: { character: 296, column: 1, line: 16 },
end: { character: 303, column: 8, line: 16 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".b + .d"',
start: { character: 323, column: 1, line: 17 },
end: { character: 330, column: 8, line: 17 }

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".a + .c"',
start: { character: 320, column: 1, line: 26 },
end: { character: 327, column: 8, line: 26 }

@ -3,61 +3,61 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".a + .c"',
start: { character: 478, column: 1, line: 23 },
end: { character: 485, column: 8, line: 23 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".a + .g"',
start: { character: 505, column: 1, line: 24 },
end: { character: 512, column: 8, line: 24 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".b + .e"',
start: { character: 532, column: 1, line: 25 },
end: { character: 539, column: 8, line: 25 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".c + .g"',
start: { character: 559, column: 1, line: 26 },
end: { character: 566, column: 8, line: 26 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".c + .k"',
start: { character: 586, column: 1, line: 27 },
end: { character: 593, column: 8, line: 27 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".d + .d"',
start: { character: 613, column: 1, line: 28 },
end: { character: 620, column: 8, line: 28 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".e + .f"',
start: { character: 640, column: 1, line: 29 },
end: { character: 647, column: 8, line: 29 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".f + .f"',
start: { character: 667, column: 1, line: 30 },
end: { character: 674, column: 8, line: 30 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".g + .j"',
start: { character: 694, column: 1, line: 31 },
end: { character: 701, column: 8, line: 31 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".g + .h + .i + .j"',
start: { character: 721, column: 1, line: 32 },
end: { character: 738, column: 18, line: 32 }

@ -3,13 +3,13 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".a + .d"',
start: { character: 171, column: 1, line: 12 },
end: { character: 178, column: 8, line: 12 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".b + .c"',
start: { character: 198, column: 1, line: 13 },
end: { character: 205, column: 8, line: 13 }

@ -3,49 +3,49 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".a + .h"',
start: { character: 1229, column: 1, line: 58 },
end: { character: 1236, column: 8, line: 58 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".a + .i"',
start: { character: 1256, column: 1, line: 59 },
end: { character: 1263, column: 8, line: 59 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".c + .h"',
start: { character: 1283, column: 1, line: 60 },
end: { character: 1290, column: 8, line: 60 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".c + .i"',
start: { character: 1310, column: 1, line: 61 },
end: { character: 1317, column: 8, line: 61 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".d + .f"',
start: { character: 1337, column: 1, line: 62 },
end: { character: 1344, column: 8, line: 62 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".d + .g"',
start: { character: 1364, column: 1, line: 63 },
end: { character: 1371, column: 8, line: 63 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".e + .g"',
start: { character: 1391, column: 1, line: 64 },
end: { character: 1398, column: 8, line: 64 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".g + .i"',
start: { character: 1418, column: 1, line: 65 },
end: { character: 1425, column: 8, line: 65 }

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ":global(input) + span"',
start: {
character: 239,
@ -17,7 +17,7 @@ export default test({
}
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ":global(input) ~ span"',
start: {
character: 279,

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".b + .c"',
start: { character: 319, column: 1, line: 18 },
end: { character: 326, column: 8, line: 18 }

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".b + .c"',
start: { character: 215, column: 1, line: 14 },
end: { character: 222, column: 8, line: 14 }

@ -3,25 +3,25 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".a + .e"',
start: { character: 242, column: 1, line: 15 },
end: { character: 249, column: 8, line: 15 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".b + .c"',
start: { character: 269, column: 1, line: 16 },
end: { character: 276, column: 8, line: 16 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".b + .d"',
start: { character: 296, column: 1, line: 17 },
end: { character: 303, column: 8, line: 17 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".c + .d"',
start: { character: 323, column: 1, line: 18 },
end: { character: 330, column: 8, line: 18 }

@ -3,19 +3,19 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".a + .b"',
start: { character: 83, column: 1, line: 9 },
end: { character: 90, column: 8, line: 9 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".b + .c"',
start: { character: 110, column: 1, line: 10 },
end: { character: 117, column: 8, line: 10 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".c + .f"',
start: { character: 137, column: 1, line: 11 },
end: { character: 144, column: 8, line: 11 }

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".not-match > * + *"',
start: { character: 50, column: 1, line: 5 },
end: { character: 68, column: 19, line: 5 }

@ -3,25 +3,25 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector "article + div"',
start: { character: 45, column: 1, line: 5 },
end: { character: 58, column: 14, line: 5 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector "span + article"',
start: { character: 81, column: 1, line: 8 },
end: { character: 95, column: 15, line: 8 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector "b + article"',
start: { character: 118, column: 1, line: 11 },
end: { character: 129, column: 12, line: 11 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector "span + div"',
start: { character: 152, column: 1, line: 14 },
end: { character: 162, column: 11, line: 14 }

@ -3,19 +3,19 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector "article > *"',
start: { character: 9, column: 1, line: 2 },
end: { character: 20, column: 12, line: 2 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector "article *"',
start: { character: 47, column: 1, line: 6 },
end: { character: 56, column: 10, line: 6 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".article > *"',
start: { character: 83, column: 1, line: 10 },
end: { character: 95, column: 13, line: 10 }

@ -4,7 +4,7 @@ export default test({
warnings: [
{
filename: 'SvelteComponent.svelte',
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector "img[alt=""]"',
start: {
character: 87,

@ -4,7 +4,7 @@ export default test({
warnings: [
{
filename: 'SvelteComponent.svelte',
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".foo"',
start: {
line: 4,
@ -20,7 +20,7 @@ export default test({
{
filename: 'SvelteComponent.svelte',
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".baz"',
start: {
line: 4,

@ -3,61 +3,61 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".fooaa"',
start: { line: 11, column: 2, character: 206 },
end: { line: 11, column: 8, character: 212 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".foobb"',
start: { line: 12, column: 2, character: 229 },
end: { line: 12, column: 8, character: 235 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".foodd"',
start: { line: 14, column: 2, character: 275 },
end: { line: 14, column: 8, character: 281 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".bbbar"',
start: { line: 20, column: 2, character: 401 },
end: { line: 20, column: 8, character: 407 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".ccbar"',
start: { line: 21, column: 2, character: 424 },
end: { line: 21, column: 8, character: 430 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".ddbar"',
start: { line: 22, column: 2, character: 447 },
end: { line: 22, column: 8, character: 453 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".fooaabar"',
start: { line: 23, column: 2, character: 470 },
end: { line: 23, column: 11, character: 479 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".foobbbar"',
start: { line: 24, column: 2, character: 496 },
end: { line: 24, column: 11, character: 505 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".fooccbar"',
start: { line: 25, column: 2, character: 522 },
end: { line: 25, column: 11, character: 531 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".unused"',
start: { line: 28, column: 2, character: 595 },
end: { line: 28, column: 9, character: 602 }

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".unused"',
start: {
character: 198,

@ -3,13 +3,13 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".hover.unused"',
start: { line: 15, column: 2, character: 261 },
end: { line: 15, column: 15, character: 274 }
},
{
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".unused"',
start: { line: 17, column: 2, character: 295 },
end: { line: 17, column: 9, character: 302 }

@ -7,7 +7,7 @@ export default test({
warnings: [
{
filename: 'SvelteComponent.svelte',
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".maybeactive"',
start: {
line: 16,

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
code: 'css_unused_selector',
end: {
character: 32,
column: 3,

@ -4,7 +4,7 @@ export default test({
warnings: [
{
filename: 'SvelteComponent.svelte',
code: 'css-unused-selector',
code: 'css_unused_selector',
message: 'Unused CSS selector ".bar"',
start: {
line: 8,

@ -4,7 +4,7 @@ const tick = () => Promise.resolve();
export default test({
warnings: [
{
code: 'avoid-is',
code: 'avoid_is',
message: 'The "is" attribute is not supported cross-browser and should be avoided',
start: {
character: 109,

@ -1,7 +1,7 @@
[
{
"code": "a11y-missing-attribute",
"message": "A11y: <img> element should have an alt attribute",
"code": "a11y_missing_attribute",
"message": "<img> element should have an alt attribute",
"start": {
"line": 1,
"column": 0
@ -12,8 +12,8 @@
}
},
{
"code": "a11y-missing-attribute",
"message": "A11y: <area> element should have an alt, aria-label or aria-labelledby attribute",
"code": "a11y_missing_attribute",
"message": "<area> element should have an alt, aria-label or aria-labelledby attribute",
"start": {
"line": 4,
"column": 1
@ -24,8 +24,8 @@
}
},
{
"code": "a11y-missing-attribute",
"message": "A11y: <object> element should have a title, aria-label or aria-labelledby attribute",
"code": "a11y_missing_attribute",
"message": "<object> element should have a title, aria-label or aria-labelledby attribute",
"start": {
"line": 7,
"column": 0
@ -36,8 +36,8 @@
}
},
{
"code": "a11y-missing-attribute",
"message": "A11y: <input type=\"image\"> element should have an alt, aria-label or aria-labelledby attribute",
"code": "a11y_missing_attribute",
"message": "<input type=\"image\"> element should have an alt, aria-label or aria-labelledby attribute",
"start": {
"line": 9,
"column": 0

@ -1,7 +1,7 @@
[
{
"code": "a11y-missing-content",
"message": "A11y: <a> element should have child content",
"code": "a11y_missing_content",
"message": "<a> element should have child content",
"start": {
"line": 1,
"column": 0

@ -1,7 +1,7 @@
[
{
"code": "a11y-missing-attribute",
"message": "A11y: <a> element should have an href attribute",
"code": "a11y_missing_attribute",
"message": "<a> element should have an href attribute",
"start": {
"line": 1,
"column": 11
@ -12,8 +12,8 @@
}
},
{
"code": "a11y-invalid-attribute",
"message": "A11y: '' is not a valid xlink:href attribute",
"code": "a11y_invalid_attribute",
"message": "'' is not a valid xlink:href attribute",
"start": {
"line": 2,
"column": 14
@ -24,8 +24,8 @@
}
},
{
"code": "a11y-invalid-attribute",
"message": "A11y: '#' is not a valid xlink:href attribute",
"code": "a11y_invalid_attribute",
"message": "'#' is not a valid xlink:href attribute",
"start": {
"line": 3,
"column": 14

@ -1,7 +1,7 @@
[
{
"code": "a11y-missing-attribute",
"message": "A11y: <a> element should have an href attribute",
"code": "a11y_missing_attribute",
"message": "<a> element should have an href attribute",
"start": {
"line": 1,
"column": 0
@ -12,8 +12,8 @@
}
},
{
"code": "a11y-invalid-attribute",
"message": "A11y: '' is not a valid href attribute",
"code": "a11y_invalid_attribute",
"message": "'' is not a valid href attribute",
"start": {
"line": 2,
"column": 3
@ -24,8 +24,8 @@
}
},
{
"code": "a11y-invalid-attribute",
"message": "A11y: '#' is not a valid href attribute",
"code": "a11y_invalid_attribute",
"message": "'#' is not a valid href attribute",
"start": {
"line": 3,
"column": 3
@ -36,8 +36,8 @@
}
},
{
"code": "a11y-invalid-attribute",
"message": "A11y: 'javascript:void(0)' is not a valid href attribute",
"code": "a11y_invalid_attribute",
"message": "'javascript:void(0)' is not a valid href attribute",
"start": {
"line": 4,
"column": 3
@ -48,8 +48,8 @@
}
},
{
"code": "a11y-missing-attribute",
"message": "A11y: <a> element should have an href attribute",
"code": "a11y_missing_attribute",
"message": "<a> element should have an href attribute",
"start": {
"line": 5,
"column": 0
@ -60,8 +60,8 @@
}
},
{
"code": "a11y-missing-attribute",
"message": "A11y: <a> element should have an href attribute",
"code": "a11y_missing_attribute",
"message": "<a> element should have an href attribute",
"start": {
"line": 6,
"column": 0

@ -1,11 +1,11 @@
[
{
"code": "a11y-aria-activedescendant-has-tabindex",
"code": "a11y_aria_activedescendant_has_tabindex",
"end": {
"column": 36,
"line": 16
},
"message": "A11y: Elements with attribute aria-activedescendant should have tabindex value",
"message": "Elements with attribute aria-activedescendant should have tabindex value",
"start": {
"column": 5,
"line": 16

@ -1,7 +1,7 @@
[
{
"code": "a11y-unknown-aria-attribute",
"message": "A11y: Unknown aria attribute 'aria-labeledby' (did you mean 'labelledby'?)",
"code": "a11y_unknown_aria_attribute_suggestion",
"message": "Unknown aria attribute 'aria-labeledby'. Did you mean 'labelledby'?",
"start": {
"line": 1,
"column": 20
@ -12,8 +12,8 @@
}
},
{
"code": "a11y-missing-attribute",
"message": "A11y: <input type=\"image\"> element should have an alt, aria-label or aria-labelledby attribute",
"code": "a11y_missing_attribute",
"message": "<input type=\"image\"> element should have an alt, aria-label or aria-labelledby attribute",
"start": {
"column": 0,
"line": 1

@ -1,7 +1,7 @@
[
{
"code": "a11y-incorrect-aria-attribute-type",
"message": "A11y: The value of 'aria-disabled' must be exactly one of true or false",
"code": "a11y_incorrect_aria_attribute_type_boolean",
"message": "The value of 'aria-disabled' must be either 'true' or 'false'",
"start": {
"line": 5,
"column": 8
@ -12,8 +12,8 @@
}
},
{
"code": "a11y-incorrect-aria-attribute-type",
"message": "A11y: The value of 'aria-disabled' must be exactly one of true or false",
"code": "a11y_incorrect_aria_attribute_type_boolean",
"message": "The value of 'aria-disabled' must be either 'true' or 'false'",
"start": {
"line": 6,
"column": 8

@ -1,7 +1,7 @@
[
{
"code": "a11y-incorrect-aria-attribute-type",
"message": "A11y: The value of 'aria-level' must be of type integer",
"code": "a11y_incorrect_aria_attribute_type_integer",
"message": "The value of 'aria-level' must be an integer",
"start": {
"line": 1,
"column": 5
@ -12,8 +12,8 @@
}
},
{
"code": "a11y-incorrect-aria-attribute-type",
"message": "A11y: The value of 'aria-level' must be of type integer",
"code": "a11y_incorrect_aria_attribute_type_integer",
"message": "The value of 'aria-level' must be an integer",
"start": {
"line": 2,
"column": 5
@ -24,8 +24,8 @@
}
},
{
"code": "a11y-incorrect-aria-attribute-type",
"message": "A11y: The value of 'aria-level' must be of type integer",
"code": "a11y_incorrect_aria_attribute_type_integer",
"message": "The value of 'aria-level' must be an integer",
"start": {
"line": 5,
"column": 5

@ -1,7 +1,7 @@
[
{
"code": "a11y-incorrect-aria-attribute-type",
"message": "A11y: The value of 'aria-valuemax' must be of type number",
"code": "a11y_incorrect_aria_attribute_type",
"message": "The value of 'aria-valuemax' must be of type number",
"start": {
"line": 1,
"column": 5
@ -12,8 +12,8 @@
}
},
{
"code": "a11y-incorrect-aria-attribute-type",
"message": "A11y: The value of 'aria-valuemax' must be of type number",
"code": "a11y_incorrect_aria_attribute_type",
"message": "The value of 'aria-valuemax' must be of type number",
"start": {
"line": 2,
"column": 5
@ -24,8 +24,8 @@
}
},
{
"code": "a11y-incorrect-aria-attribute-type",
"message": "A11y: The value of 'aria-valuemax' must be of type number",
"code": "a11y_incorrect_aria_attribute_type",
"message": "The value of 'aria-valuemax' must be of type number",
"start": {
"line": 5,
"column": 5

@ -1,7 +1,7 @@
[
{
"code": "a11y-incorrect-aria-attribute-type",
"message": "A11y: The value of 'aria-label' must be of type string",
"code": "a11y_incorrect_aria_attribute_type",
"message": "The value of 'aria-label' must be of type string",
"start": {
"line": 1,
"column": 5

@ -1,7 +1,7 @@
[
{
"code": "a11y-incorrect-aria-attribute-type",
"message": "A11y: The value of 'aria-sort' must be exactly one of ascending, descending, none, other",
"code": "a11y_incorrect_aria_attribute_type_token",
"message": "The value of 'aria-sort' must be exactly one of \"ascending\", \"descending\", \"none\" or \"other\"",
"start": {
"line": 1,
"column": 5
@ -12,8 +12,8 @@
}
},
{
"code": "a11y-incorrect-aria-attribute-type",
"message": "A11y: The value of 'aria-sort' must be exactly one of ascending, descending, none, other",
"code": "a11y_incorrect_aria_attribute_type_token",
"message": "The value of 'aria-sort' must be exactly one of \"ascending\", \"descending\", \"none\" or \"other\"",
"start": {
"line": 2,
"column": 5
@ -24,8 +24,8 @@
}
},
{
"code": "a11y-incorrect-aria-attribute-type",
"message": "A11y: The value of 'aria-sort' must be exactly one of ascending, descending, none, other",
"code": "a11y_incorrect_aria_attribute_type_token",
"message": "The value of 'aria-sort' must be exactly one of \"ascending\", \"descending\", \"none\" or \"other\"",
"start": {
"line": 3,
"column": 5
@ -36,8 +36,8 @@
}
},
{
"code": "a11y-incorrect-aria-attribute-type",
"message": "A11y: The value of 'aria-sort' must be exactly one of ascending, descending, none, other",
"code": "a11y_incorrect_aria_attribute_type_token",
"message": "The value of 'aria-sort' must be exactly one of \"ascending\", \"descending\", \"none\" or \"other\"",
"start": {
"line": 6,
"column": 5

@ -1,7 +1,7 @@
[
{
"code": "a11y-incorrect-aria-attribute-type",
"message": "A11y: The value of 'aria-relevant' must be a space-separated list of one or more of additions, all, removals, text",
"code": "a11y_incorrect_aria_attribute_type_tokenlist",
"message": "The value of 'aria-relevant' must be a space-separated list of one or more of \"additions\", \"all\", \"removals\" or \"text\"",
"start": {
"line": 1,
"column": 5
@ -12,8 +12,8 @@
}
},
{
"code": "a11y-incorrect-aria-attribute-type",
"message": "A11y: The value of 'aria-relevant' must be a space-separated list of one or more of additions, all, removals, text",
"code": "a11y_incorrect_aria_attribute_type_tokenlist",
"message": "The value of 'aria-relevant' must be a space-separated list of one or more of \"additions\", \"all\", \"removals\" or \"text\"",
"start": {
"line": 2,
"column": 5
@ -24,8 +24,8 @@
}
},
{
"code": "a11y-incorrect-aria-attribute-type",
"message": "A11y: The value of 'aria-relevant' must be a space-separated list of one or more of additions, all, removals, text",
"code": "a11y_incorrect_aria_attribute_type_tokenlist",
"message": "The value of 'aria-relevant' must be a space-separated list of one or more of \"additions\", \"all\", \"removals\" or \"text\"",
"start": {
"line": 3,
"column": 5
@ -36,8 +36,8 @@
}
},
{
"code": "a11y-incorrect-aria-attribute-type",
"message": "A11y: The value of 'aria-relevant' must be a space-separated list of one or more of additions, all, removals, text",
"code": "a11y_incorrect_aria_attribute_type_tokenlist",
"message": "The value of 'aria-relevant' must be a space-separated list of one or more of \"additions\", \"all\", \"removals\" or \"text\"",
"start": {
"line": 6,
"column": 5
@ -48,8 +48,8 @@
}
},
{
"code": "a11y-incorrect-aria-attribute-type",
"message": "A11y: The value of 'aria-relevant' must be a space-separated list of one or more of additions, all, removals, text",
"code": "a11y_incorrect_aria_attribute_type_tokenlist",
"message": "The value of 'aria-relevant' must be a space-separated list of one or more of \"additions\", \"all\", \"removals\" or \"text\"",
"start": {
"line": 7,
"column": 5

@ -1,7 +1,7 @@
[
{
"code": "a11y-incorrect-aria-attribute-type",
"message": "A11y: The value of 'aria-checked' must be exactly one of true, false, or mixed",
"code": "a11y_incorrect_aria_attribute_type_tristate",
"message": "The value of 'aria-checked' must be exactly one of true, false, or mixed",
"start": {
"line": 5,
"column": 5
@ -12,8 +12,8 @@
}
},
{
"code": "a11y-incorrect-aria-attribute-type",
"message": "A11y: The value of 'aria-checked' must be exactly one of true, false, or mixed",
"code": "a11y_incorrect_aria_attribute_type_tristate",
"message": "The value of 'aria-checked' must be exactly one of true, false, or mixed",
"start": {
"line": 6,
"column": 5

@ -1,7 +1,7 @@
[
{
"code": "a11y-unknown-role",
"message": "A11y: Unknown role 'toooltip' (did you mean 'tooltip'?)",
"code": "a11y_unknown_role_suggestion",
"message": "Unknown role 'toooltip'. Did you mean 'tooltip'?",
"start": {
"line": 6,
"column": 5
@ -12,8 +12,8 @@
}
},
{
"code": "a11y-unknown-role",
"message": "A11y: Unknown role 'toooltip' (did you mean 'tooltip'?)",
"code": "a11y_unknown_role_suggestion",
"message": "Unknown role 'toooltip'. Did you mean 'tooltip'?",
"start": {
"line": 7,
"column": 5

@ -1,7 +1,7 @@
[
{
"code": "a11y-aria-attributes",
"message": "A11y: <meta> should not have aria-* attributes",
"code": "a11y_aria_attributes",
"message": "<meta> should not have aria-* attributes",
"start": {
"line": 1,
"column": 6
@ -12,8 +12,8 @@
}
},
{
"code": "a11y-misplaced-role",
"message": "A11y: <meta> should not have role attribute",
"code": "a11y_misplaced_role",
"message": "<meta> should not have role attribute",
"start": {
"line": 2,
"column": 6

@ -1,35 +1,35 @@
[
{
"code": "a11y-autocomplete-valid",
"code": "a11y_autocomplete_valid",
"end": {
"column": 31,
"line": 25
},
"message": "A11y: The value 'true' is not supported by the attribute 'autocomplete' on element <input type=\"text\">",
"message": "The value 'true' is not supported by the attribute 'autocomplete' on element <input type=\"text\">",
"start": {
"column": 19,
"line": 25
}
},
{
"code": "a11y-autocomplete-valid",
"code": "a11y_autocomplete_valid",
"end": {
"column": 43,
"line": 26
},
"message": "A11y: The value 'incorrect' is not supported by the attribute 'autocomplete' on element <input type=\"text\">",
"message": "The value 'incorrect' is not supported by the attribute 'autocomplete' on element <input type=\"text\">",
"start": {
"column": 19,
"line": 26
}
},
{
"code": "a11y-autocomplete-valid",
"code": "a11y_autocomplete_valid",
"end": {
"column": 42,
"line": 27
},
"message": "A11y: The value 'webauthn' is not supported by the attribute 'autocomplete' on element <input type=\"text\">",
"message": "The value 'webauthn' is not supported by the attribute 'autocomplete' on element <input type=\"text\">",
"start": {
"column": 19,
"line": 27

@ -9,22 +9,22 @@
</script>
<!-- should warn -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div on:click={noop}></div>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div on:click={noop} aria-hidden="false"></div>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<section on:click={noop}></section>
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
<main on:click={noop}></main>
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
<article on:click={noop}></article>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<header on:click={noop}></header>
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
<footer on:click={noop}></footer>
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
<footer onclick={noop}></footer>
<!-- should not warn -->
@ -37,32 +37,32 @@
<input type="button" on:click={noop} />
<input type={dynamicTypeValue} on:click={noop} />
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div on:click={noop} {...props}></div>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div on:click={noop} on:keydown={noop}></div>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div on:click={noop} on:keyup={noop}></div>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div on:click={noop} on:keypress={noop}></div>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div on:click={noop} on:keydown={noop} on:keyup={noop}></div>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div on:click={noop} on:keyup={noop} on:keypress={noop}></div>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div on:click={noop} on:keypress={noop} on:keydown={noop}></div>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div on:click={noop} on:keydown={noop} on:keyup={noop} on:keypress={noop}></div>
<input on:click={noop} type="hidden" />
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div on:click={noop} aria-hidden></div>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div on:click={noop} aria-hidden="true"></div>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div on:click={noop} aria-hidden="false" on:keydown={noop}></div>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div on:click={noop} aria-hidden={dynamicAriaHiddenValue}></div>
<div on:click={noop} role="presentation"></div>
@ -70,5 +70,5 @@
<div on:click={noop} role={dynamicRole}></div>
<div onclick={noop} role={dynamicRole}></div>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<svelte:element this={Math.random() ? 'button' : 'div'} on:click={noop} />

@ -1,7 +1,7 @@
[
{
"code": "a11y-click-events-have-key-events",
"message": "A11y: visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type=\"button\"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.",
"code": "a11y_click_events_have_key_events",
"message": "Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type=\"button\"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.",
"start": {
"line": 13,
"column": 0
@ -12,8 +12,8 @@
}
},
{
"code": "a11y-click-events-have-key-events",
"message": "A11y: visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type=\"button\"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.",
"code": "a11y_click_events_have_key_events",
"message": "Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type=\"button\"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.",
"start": {
"line": 15,
"column": 0
@ -24,8 +24,8 @@
}
},
{
"code": "a11y-click-events-have-key-events",
"message": "A11y: visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type=\"button\"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.",
"code": "a11y_click_events_have_key_events",
"message": "Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type=\"button\"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.",
"start": {
"line": 18,
"column": 0
@ -36,8 +36,8 @@
}
},
{
"code": "a11y-click-events-have-key-events",
"message": "A11y: visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type=\"button\"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.",
"code": "a11y_click_events_have_key_events",
"message": "Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type=\"button\"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.",
"start": {
"line": 20,
"column": 0
@ -48,8 +48,8 @@
}
},
{
"code": "a11y-click-events-have-key-events",
"message": "A11y: visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type=\"button\"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.",
"code": "a11y_click_events_have_key_events",
"message": "Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type=\"button\"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.",
"start": {
"line": 22,
"column": 0
@ -60,8 +60,8 @@
}
},
{
"code": "a11y-click-events-have-key-events",
"message": "A11y: visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type=\"button\"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.",
"code": "a11y_click_events_have_key_events",
"message": "Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type=\"button\"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.",
"start": {
"line": 24,
"column": 0
@ -72,8 +72,8 @@
}
},
{
"code": "a11y-click-events-have-key-events",
"message": "A11y: visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type=\"button\"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.",
"code": "a11y_click_events_have_key_events",
"message": "Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type=\"button\"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.",
"start": {
"line": 26,
"column": 0
@ -84,8 +84,8 @@
}
},
{
"code": "a11y-click-events-have-key-events",
"message": "A11y: visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type=\"button\"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.",
"code": "a11y_click_events_have_key_events",
"message": "Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type=\"button\"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.",
"start": {
"line": 28,
"column": 0

@ -1,7 +1,7 @@
[
{
"code": "a11y-structure",
"message": "A11y: <figcaption> must be first or last child of <figure>",
"code": "a11y_figcaption_index",
"message": "`<figcaption>` must be first or last child of `<figure>`",
"start": {
"line": 4,
"column": 1
@ -12,8 +12,8 @@
}
},
{
"code": "a11y-structure",
"message": "A11y: <figcaption> must be an immediate child of <figure>",
"code": "a11y_figcaption_parent",
"message": "`<figcaption>` must be an immediate child of `<figure>`",
"start": {
"line": 15,
"column": 2

@ -1,7 +1,7 @@
[
{
"code": "a11y-missing-content",
"message": "A11y: <h1> element should have child content",
"code": "a11y_missing_content",
"message": "<h1> element should have child content",
"start": {
"line": 1,
"column": 0
@ -12,8 +12,8 @@
}
},
{
"code": "a11y-hidden",
"message": "A11y: <h2> element should not be hidden",
"code": "a11y_hidden",
"message": "<h2> element should not be hidden",
"start": {
"line": 2,
"column": 4

@ -1,7 +1,7 @@
[
{
"code": "a11y-missing-attribute",
"message": "A11y: <html> element should have a lang attribute",
"code": "a11y_missing_attribute",
"message": "<html> element should have a lang attribute",
"start": {
"column": 0,
"line": 9

@ -1,7 +1,7 @@
[
{
"code": "a11y-missing-attribute",
"message": "A11y: <iframe> element should have a title attribute",
"code": "a11y_missing_attribute",
"message": "<iframe> element should have a title attribute",
"start": {
"line": 5,
"column": 0

@ -1,7 +1,7 @@
[
{
"code": "a11y-img-redundant-alt",
"message": "A11y: Screenreaders already announce <img> elements as an image.",
"code": "a11y_img_redundant_alt",
"message": "Screenreaders already announce <img> elements as an image.",
"end": {
"column": 49,
"line": 3
@ -12,8 +12,8 @@
}
},
{
"code": "a11y-img-redundant-alt",
"message": "A11y: Screenreaders already announce <img> elements as an image.",
"code": "a11y_img_redundant_alt",
"message": "Screenreaders already announce <img> elements as an image.",
"end": {
"column": 45,
"line": 4
@ -24,8 +24,8 @@
}
},
{
"code": "a11y-img-redundant-alt",
"message": "A11y: Screenreaders already announce <img> elements as an image.",
"code": "a11y_img_redundant_alt",
"message": "Screenreaders already announce <img> elements as an image.",
"end": {
"column": 52,
"line": 5

@ -1,275 +1,275 @@
[
{
"code": "a11y-interactive-supports-focus",
"code": "a11y_interactive_supports_focus",
"end": {
"column": 48,
"line": 11
},
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
"message": "Elements with the 'button' interactive role must have a tabindex value.",
"start": {
"column": 0,
"line": 11
}
},
{
"code": "a11y-interactive-supports-focus",
"code": "a11y_interactive_supports_focus",
"end": {
"column": 51,
"line": 12
},
"message": "A11y: Elements with the 'menuitem' interactive role must have a tabindex value.",
"message": "Elements with the 'menuitem' interactive role must have a tabindex value.",
"start": {
"column": 0,
"line": 12
}
},
{
"code": "a11y-interactive-supports-focus",
"code": "a11y_interactive_supports_focus",
"end": {
"column": 45,
"line": 13
},
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
"message": "Elements with the 'button' interactive role must have a tabindex value.",
"start": {
"column": 0,
"line": 13
}
},
{
"code": "a11y-interactive-supports-focus",
"code": "a11y_interactive_supports_focus",
"end": {
"column": 72,
"line": 14
},
"message": "A11y: Elements with the 'menuitem' interactive role must have a tabindex value.",
"message": "Elements with the 'menuitem' interactive role must have a tabindex value.",
"start": {
"column": 0,
"line": 14
}
},
{
"code": "a11y-interactive-supports-focus",
"code": "a11y_interactive_supports_focus",
"end": {
"column": 51,
"line": 15
},
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
"message": "Elements with the 'button' interactive role must have a tabindex value.",
"start": {
"column": 0,
"line": 15
}
},
{
"code": "a11y-interactive-supports-focus",
"code": "a11y_interactive_supports_focus",
"end": {
"column": 52,
"line": 16
},
"message": "A11y: Elements with the 'menuitem' interactive role must have a tabindex value.",
"message": "Elements with the 'menuitem' interactive role must have a tabindex value.",
"start": {
"column": 0,
"line": 16
}
},
{
"code": "a11y-interactive-supports-focus",
"code": "a11y_interactive_supports_focus",
"end": {
"column": 44,
"line": 17
},
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
"message": "Elements with the 'button' interactive role must have a tabindex value.",
"start": {
"column": 0,
"line": 17
}
},
{
"code": "a11y-interactive-supports-focus",
"code": "a11y_interactive_supports_focus",
"end": {
"column": 51,
"line": 18
},
"message": "A11y: Elements with the 'menuitem' interactive role must have a tabindex value.",
"message": "Elements with the 'menuitem' interactive role must have a tabindex value.",
"start": {
"column": 0,
"line": 18
}
},
{
"code": "a11y-interactive-supports-focus",
"code": "a11y_interactive_supports_focus",
"end": {
"column": 49,
"line": 19
},
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
"message": "Elements with the 'button' interactive role must have a tabindex value.",
"start": {
"column": 0,
"line": 19
}
},
{
"code": "a11y-interactive-supports-focus",
"code": "a11y_interactive_supports_focus",
"end": {
"column": 52,
"line": 20
},
"message": "A11y: Elements with the 'menuitem' interactive role must have a tabindex value.",
"message": "Elements with the 'menuitem' interactive role must have a tabindex value.",
"start": {
"column": 0,
"line": 20
}
},
{
"code": "a11y-interactive-supports-focus",
"code": "a11y_interactive_supports_focus",
"end": {
"column": 49,
"line": 21
},
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
"message": "Elements with the 'button' interactive role must have a tabindex value.",
"start": {
"column": 0,
"line": 21
}
},
{
"code": "a11y-interactive-supports-focus",
"code": "a11y_interactive_supports_focus",
"end": {
"column": 52,
"line": 22
},
"message": "A11y: Elements with the 'menuitem' interactive role must have a tabindex value.",
"message": "Elements with the 'menuitem' interactive role must have a tabindex value.",
"start": {
"column": 0,
"line": 22
}
},
{
"code": "a11y-interactive-supports-focus",
"code": "a11y_interactive_supports_focus",
"end": {
"column": 49,
"line": 23
},
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
"message": "Elements with the 'button' interactive role must have a tabindex value.",
"start": {
"column": 0,
"line": 23
}
},
{
"code": "a11y-interactive-supports-focus",
"code": "a11y_interactive_supports_focus",
"end": {
"column": 48,
"line": 24
},
"message": "A11y: Elements with the 'menuitem' interactive role must have a tabindex value.",
"message": "Elements with the 'menuitem' interactive role must have a tabindex value.",
"start": {
"column": 0,
"line": 24
}
},
{
"code": "a11y-interactive-supports-focus",
"code": "a11y_interactive_supports_focus",
"end": {
"column": 49,
"line": 25
},
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
"message": "Elements with the 'button' interactive role must have a tabindex value.",
"start": {
"column": 0,
"line": 25
}
},
{
"code": "a11y-interactive-supports-focus",
"code": "a11y_interactive_supports_focus",
"end": {
"column": 54,
"line": 26
},
"message": "A11y: Elements with the 'menuitem' interactive role must have a tabindex value.",
"message": "Elements with the 'menuitem' interactive role must have a tabindex value.",
"start": {
"column": 0,
"line": 26
}
},
{
"code": "a11y-interactive-supports-focus",
"code": "a11y_interactive_supports_focus",
"end": {
"column": 50,
"line": 27
},
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
"message": "Elements with the 'button' interactive role must have a tabindex value.",
"start": {
"column": 0,
"line": 27
}
},
{
"code": "a11y-interactive-supports-focus",
"code": "a11y_interactive_supports_focus",
"end": {
"column": 53,
"line": 28
},
"message": "A11y: Elements with the 'menuitem' interactive role must have a tabindex value.",
"message": "Elements with the 'menuitem' interactive role must have a tabindex value.",
"start": {
"column": 0,
"line": 28
}
},
{
"code": "a11y-interactive-supports-focus",
"code": "a11y_interactive_supports_focus",
"end": {
"column": 48,
"line": 29
},
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
"message": "Elements with the 'button' interactive role must have a tabindex value.",
"start": {
"column": 0,
"line": 29
}
},
{
"code": "a11y-mouse-events-have-key-events",
"code": "a11y_mouse_events_have_key_events",
"end": {
"column": 48,
"line": 29
},
"message": "A11y: 'mouseout' event must be accompanied by 'blur' event",
"message": "'mouseout' event must be accompanied by 'blur' event",
"start": {
"column": 0,
"line": 29
}
},
{
"code": "a11y-interactive-supports-focus",
"code": "a11y_interactive_supports_focus",
"end": {
"column": 53,
"line": 30
},
"message": "A11y: Elements with the 'menuitem' interactive role must have a tabindex value.",
"message": "Elements with the 'menuitem' interactive role must have a tabindex value.",
"start": {
"column": 0,
"line": 30
}
},
{
"code": "a11y-mouse-events-have-key-events",
"code": "a11y_mouse_events_have_key_events",
"end": {
"column": 53,
"line": 30
},
"message": "A11y: 'mouseover' event must be accompanied by 'focus' event",
"message": "'mouseover' event must be accompanied by 'focus' event",
"start": {
"column": 0,
"line": 30
}
},
{
"code": "a11y-interactive-supports-focus",
"code": "a11y_interactive_supports_focus",
"end": {
"column": 47,
"line": 31
},
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
"message": "Elements with the 'button' interactive role must have a tabindex value.",
"start": {
"column": 0,
"line": 31

@ -1,23 +1,23 @@
[
{
"code": "a11y-label-has-associated-control",
"code": "a11y_label_has_associated_control",
"end": {
"column": 16,
"line": 5
},
"message": "A11y: A form label must be associated with a control.",
"message": "A form label must be associated with a control.",
"start": {
"column": 0,
"line": 5
}
},
{
"code": "a11y-label-has-associated-control",
"code": "a11y_label_has_associated_control",
"end": {
"column": 30,
"line": 10
},
"message": "A11y: A form label must be associated with a control.",
"message": "A form label must be associated with a control.",
"start": {
"column": 0,
"line": 10

@ -1,47 +1,47 @@
[
{
"code": "a11y-media-has-caption",
"code": "a11y_media_has_caption",
"end": {
"column": 15,
"line": 2
},
"message": "A11y: <video> elements must have a <track kind=\"captions\">",
"message": "<video> elements must have a <track kind=\"captions\">",
"start": {
"column": 0,
"line": 2
}
},
{
"code": "a11y-media-has-caption",
"code": "a11y_media_has_caption",
"end": {
"column": 24,
"line": 3
},
"message": "A11y: <video> elements must have a <track kind=\"captions\">",
"message": "<video> elements must have a <track kind=\"captions\">",
"start": {
"column": 0,
"line": 3
}
},
{
"code": "a11y-media-has-caption",
"code": "a11y_media_has_caption",
"end": {
"column": 27,
"line": 5
},
"message": "A11y: <video> elements must have a <track kind=\"captions\">",
"message": "<video> elements must have a <track kind=\"captions\">",
"start": {
"column": 0,
"line": 5
}
},
{
"code": "a11y-media-has-caption",
"code": "a11y_media_has_caption",
"end": {
"column": 35,
"line": 6
},
"message": "A11y: <video> elements must have a <track kind=\"captions\">",
"message": "<video> elements must have a <track kind=\"captions\">",
"start": {
"column": 0,
"line": 6

@ -7,15 +7,15 @@
};
</script>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div on:mouseover={() => void 0}></div>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div on:mouseover={() => void 0} on:focus={() => void 0}></div>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div on:mouseover={() => void 0} {...otherProps}></div>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div on:mouseout={() => void 0}></div>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div on:mouseout={() => void 0} on:blur={() => void 0}></div>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div on:mouseout={() => void 0} {...otherProps}></div>

@ -1,47 +1,47 @@
[
{
"code": "a11y-mouse-events-have-key-events",
"code": "a11y_mouse_events_have_key_events",
"end": {
"column": 39,
"line": 11
},
"message": "A11y: 'mouseover' event must be accompanied by 'focus' event",
"message": "'mouseover' event must be accompanied by 'focus' event",
"start": {
"column": 0,
"line": 11
}
},
{
"code": "a11y-mouse-events-have-key-events",
"code": "a11y_mouse_events_have_key_events",
"end": {
"column": 55,
"line": 15
},
"message": "A11y: 'mouseover' event must be accompanied by 'focus' event",
"message": "'mouseover' event must be accompanied by 'focus' event",
"start": {
"column": 0,
"line": 15
}
},
{
"code": "a11y-mouse-events-have-key-events",
"code": "a11y_mouse_events_have_key_events",
"end": {
"column": 38,
"line": 17
},
"message": "A11y: 'mouseout' event must be accompanied by 'blur' event",
"message": "'mouseout' event must be accompanied by 'blur' event",
"start": {
"column": 0,
"line": 17
}
},
{
"code": "a11y-mouse-events-have-key-events",
"code": "a11y_mouse_events_have_key_events",
"end": {
"column": 54,
"line": 21
},
"message": "A11y: 'mouseout' event must be accompanied by 'blur' event",
"message": "'mouseout' event must be accompanied by 'blur' event",
"start": {
"column": 0,
"line": 21

@ -1,143 +1,143 @@
[
{
"code": "a11y-no-abstract-role",
"code": "a11y_no_abstract_role",
"end": {
"column": 19,
"line": 1
},
"message": "A11y: Abstract role 'command' is forbidden",
"message": "Abstract role 'command' is forbidden",
"start": {
"column": 5,
"line": 1
}
},
{
"code": "a11y-no-abstract-role",
"code": "a11y_no_abstract_role",
"end": {
"column": 21,
"line": 2
},
"message": "A11y: Abstract role 'composite' is forbidden",
"message": "Abstract role 'composite' is forbidden",
"start": {
"column": 5,
"line": 2
}
},
{
"code": "a11y-no-abstract-role",
"code": "a11y_no_abstract_role",
"end": {
"column": 17,
"line": 3
},
"message": "A11y: Abstract role 'input' is forbidden",
"message": "Abstract role 'input' is forbidden",
"start": {
"column": 5,
"line": 3
}
},
{
"code": "a11y-no-abstract-role",
"code": "a11y_no_abstract_role",
"end": {
"column": 20,
"line": 4
},
"message": "A11y: Abstract role 'landmark' is forbidden",
"message": "Abstract role 'landmark' is forbidden",
"start": {
"column": 5,
"line": 4
}
},
{
"code": "a11y-no-abstract-role",
"code": "a11y_no_abstract_role",
"end": {
"column": 17,
"line": 5
},
"message": "A11y: Abstract role 'range' is forbidden",
"message": "Abstract role 'range' is forbidden",
"start": {
"column": 5,
"line": 5
}
},
{
"code": "a11y-no-abstract-role",
"code": "a11y_no_abstract_role",
"end": {
"column": 20,
"line": 6
},
"message": "A11y: Abstract role 'roletype' is forbidden",
"message": "Abstract role 'roletype' is forbidden",
"start": {
"column": 5,
"line": 6
}
},
{
"code": "a11y-no-abstract-role",
"code": "a11y_no_abstract_role",
"end": {
"column": 19,
"line": 7
},
"message": "A11y: Abstract role 'section' is forbidden",
"message": "Abstract role 'section' is forbidden",
"start": {
"column": 5,
"line": 7
}
},
{
"code": "a11y-no-abstract-role",
"code": "a11y_no_abstract_role",
"end": {
"column": 23,
"line": 8
},
"message": "A11y: Abstract role 'sectionhead' is forbidden",
"message": "Abstract role 'sectionhead' is forbidden",
"start": {
"column": 5,
"line": 8
}
},
{
"code": "a11y-no-abstract-role",
"code": "a11y_no_abstract_role",
"end": {
"column": 18,
"line": 9
},
"message": "A11y: Abstract role 'select' is forbidden",
"message": "Abstract role 'select' is forbidden",
"start": {
"column": 5,
"line": 9
}
},
{
"code": "a11y-no-abstract-role",
"code": "a11y_no_abstract_role",
"end": {
"column": 21,
"line": 10
},
"message": "A11y: Abstract role 'structure' is forbidden",
"message": "Abstract role 'structure' is forbidden",
"start": {
"column": 5,
"line": 10
}
},
{
"code": "a11y-no-abstract-role",
"code": "a11y_no_abstract_role",
"end": {
"column": 18,
"line": 11
},
"message": "A11y: Abstract role 'widget' is forbidden",
"message": "Abstract role 'widget' is forbidden",
"start": {
"column": 5,
"line": 11
}
},
{
"code": "a11y-no-abstract-role",
"code": "a11y_no_abstract_role",
"end": {
"column": 18,
"line": 12
},
"message": "A11y: Abstract role 'window' is forbidden",
"message": "Abstract role 'window' is forbidden",
"start": {
"column": 5,
"line": 12

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save