Skip to content

Commit 7b55bd4

Browse files
authored
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
1 parent 5405ec6 commit 7b55bd4

File tree

164 files changed

+2475
-1779
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

164 files changed

+2475
-1779
lines changed

.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ packages/**/npm/**/*
44
packages/**/config/*.js
55
packages/svelte/messages/**/*.md
66
packages/svelte/src/compiler/errors.js
7+
packages/svelte/src/compiler/warnings.js
78
packages/svelte/tests/**/*.svelte
89
packages/svelte/tests/**/_expected*
910
packages/svelte/tests/**/_actual*
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
## a11y_aria_attributes
2+
3+
<%name%> should not have aria-* attributes
4+
5+
## a11y_unknown_aria_attribute
6+
7+
Unknown aria attribute 'aria-%attribute%'
8+
9+
## a11y_unknown_aria_attribute_suggestion
10+
11+
Unknown aria attribute 'aria-%attribute%'. Did you mean '%suggestion%'?
12+
13+
## a11y_hidden
14+
15+
<%name%> element should not be hidden
16+
17+
## a11y_incorrect_aria_attribute_type_boolean
18+
19+
The value of '%attribute%' must be either 'true' or 'false'
20+
21+
## a11y_incorrect_aria_attribute_type_integer
22+
23+
The value of '%attribute%' must be an integer
24+
25+
## a11y_incorrect_aria_attribute_type_id
26+
27+
The value of '%attribute%' must be a string that represents a DOM element ID
28+
29+
## a11y_incorrect_aria_attribute_type_idlist
30+
31+
The value of '%attribute%' must be a space-separated list of strings that represent DOM element IDs
32+
33+
## a11y_incorrect_aria_attribute_type_tristate
34+
35+
The value of '%attribute%' must be exactly one of true, false, or mixed
36+
37+
## a11y_incorrect_aria_attribute_type_token
38+
39+
The value of '%attribute%' must be exactly one of %values%
40+
41+
## a11y_incorrect_aria_attribute_type_tokenlist
42+
43+
The value of '%attribute%' must be a space-separated list of one or more of %values%
44+
45+
## a11y_incorrect_aria_attribute_type
46+
47+
The value of '%attribute%' must be of type %type%
48+
49+
## a11y_aria_activedescendant_has_tabindex
50+
51+
Elements with attribute aria-activedescendant should have tabindex value
52+
53+
## a11y_misplaced_role
54+
55+
<%name%> should not have role attribute
56+
57+
## a11y_no_abstract_role
58+
59+
Abstract role '%role%' is forbidden
60+
61+
## a11y_unknown_role
62+
63+
Unknown role '%role%'
64+
65+
## a11y_unknown_role_suggestion
66+
67+
Unknown role '%role%'. Did you mean '%suggestion%'?
68+
69+
## a11y_no_redundant_roles
70+
71+
Redundant role '%role%'
72+
73+
## a11y_role_has_required_aria_props
74+
75+
Elements with the ARIA role "%role%" must have the following attributes defined: %props%
76+
77+
## a11y_interactive_supports_focus
78+
79+
Elements with the '%role%' interactive role must have a tabindex value.
80+
81+
## a11y_no_interactive_element_to_noninteractive_role
82+
83+
<%element%> cannot have role '%role%'
84+
85+
## a11y_no_noninteractive_element_to_interactive_role
86+
87+
Non-interactive element <%element%> cannot have interactive role '%role%'
88+
89+
## a11y_accesskey
90+
91+
Avoid using accesskey
92+
93+
## a11y_autofocus
94+
95+
Avoid using autofocus
96+
97+
## a11y_misplaced_scope
98+
99+
The scope attribute should only be used with <th> elements
100+
101+
## a11y_positive_tabindex
102+
103+
Avoid tabindex values above zero
104+
105+
## a11y_click_events_have_key_events
106+
107+
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.
108+
109+
## a11y_no_noninteractive_tabindex
110+
111+
noninteractive element cannot have nonnegative tabIndex value
112+
113+
## a11y_role_supports_aria_props
114+
115+
The attribute '%attribute%' is not supported by the role '%role%'
116+
117+
## a11y_role_supports_aria_props_implicit
118+
119+
The attribute '%attribute%' is not supported by the role '%role%'. This role is implicit on the element <%name%>
120+
121+
## a11y_no_noninteractive_element_interactions
122+
123+
Non-interactive element <%element%> should not be assigned mouse or keyboard event listeners.
124+
125+
## a11y_no_static_element_interactions
126+
127+
<%element%> with a %handler% handler must have an ARIA role
128+
129+
## a11y_invalid_attribute
130+
131+
'%href_value%' is not a valid %href_attribute% attribute
132+
133+
## a11y_missing_attribute
134+
135+
<%name%> element should have %article% %sequence% attribute
136+
137+
## a11y_autocomplete_valid
138+
139+
The value '%value%' is not supported by the attribute 'autocomplete' on element <input type="%type%">
140+
141+
## a11y_img_redundant_alt
142+
143+
Screenreaders already announce <img> elements as an image.
144+
145+
## a11y_label_has_associated_control
146+
147+
A form label must be associated with a control.
148+
149+
## a11y_media_has_caption
150+
151+
<video> elements must have a <track kind="captions">
152+
153+
## a11y_distracting_elements
154+
155+
Avoid <%name%> elements
156+
157+
## a11y_figcaption_parent
158+
159+
`<figcaption>` must be an immediate child of `<figure>`
160+
161+
## a11y_figcaption_index
162+
163+
`<figcaption>` must be first or last child of `<figure>`
164+
165+
## a11y_mouse_events_have_key_events
166+
167+
'%event%' event must be accompanied by '%accompanied_by%' event
168+
169+
## a11y_missing_content
170+
171+
<%name%> element should have child content
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
## avoid_is
2+
3+
The "is" attribute is not supported cross-browser and should be avoided
4+
5+
## global_event_reference
6+
7+
You are referencing globalThis.%name%. Did you forget to declare a variable with that name?
8+
9+
## illegal_attribute_character
10+
11+
Attributes should not contain ':' characters to prevent ambiguity with Svelte directives
12+
13+
## invalid_html_attribute
14+
15+
'%wrong%' is not a valid HTML attribute. Did you mean '%right%'?
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## empty_block
2+
3+
Empty block
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## component_name_lowercase
2+
3+
<%name%> will be treated as an HTML element unless it begins with a capital letter
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## css_unused_selector
2+
3+
Unused CSS selector "%name%"
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
## no_reactive_declaration
2+
3+
Reactive declarations only exist at the top level of the instance script
4+
5+
## module_script_reactive_declaration
6+
7+
All dependencies of the reactive declaration are declared in a module script and will not be reactive
8+
9+
## unused_export_let
10+
11+
Component has unused export property '%name%'. If it is for external reference only, please consider using `export const %name%`
12+
13+
## deprecated_slot_element
14+
15+
Using <slot> to render parent content is deprecated. Use {@render ...} tags instead.
16+
17+
## deprecated_event_handler
18+
19+
Using on:%name% to listen to the %name% event is is deprecated. Use the event attribute on%name% instead.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## invalid_self_closing_tag
2+
3+
Self-closing HTML tags for non-void elements are ambiguous — use <%name% ...></%name%> rather than <%name% ... />
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## missing_custom_element_compile_option
2+
3+
The 'customElement' option is used when generating a custom element. Did you forget the 'customElement: true' compile option?
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
## avoid_inline_class
2+
3+
Avoid 'new class' — instead, declare the class at the top level scope
4+
5+
## avoid_nested_class
6+
7+
Avoid declaring classes below the top level scope
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
## store_with_rune_name
2+
3+
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
4+
5+
## non_state_reference
6+
7+
`%name%` is updated, but is not declared with `$state(...)`. Changing its value will not correctly trigger updates
8+
9+
## derived_iife
10+
11+
Use `$derived.by(() => {...})` instead of `$derived((() => {...})())`
12+
13+
## invalid_props_declaration
14+
15+
Component properties are declared using `$props()` in runes mode. Did you forget to call the function?
16+
17+
## invalid_bindable_declaration
18+
19+
Bindable component properties are declared using `$bindable()` in runes mode. Did you forget to call the function?
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
## static_state_reference
2+
3+
State referenced in its own scope will never update. Did you mean to reference it inside a closure?
4+
5+
## invalid_rest_eachblock_binding
6+
7+
The rest operator (...) will create a new object and binding '%name%' with the original object will not work

packages/svelte/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@
9999
"templating"
100100
],
101101
"scripts": {
102-
"build": "rollup -c && pnpm generate:types && node scripts/check-treeshakeability.js",
103-
"dev": "rollup -cw",
102+
"build": "node scripts/process-messages && rollup -c && pnpm generate:types && node scripts/check-treeshakeability.js",
103+
"dev": "node scripts/process-messages && rollup -cw",
104104
"check": "tsc && cd ./tests/types && tsc",
105105
"check:watch": "tsc --watch",
106106
"generate:version": "node ./scripts/generate-version.js",

packages/svelte/scripts/process-messages/index.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,20 @@ function transform(name, dest) {
111111
const value = node.value
112112
.split('\n')
113113
.map((line) => {
114+
if (line === ' * MESSAGE') {
115+
return message
116+
.split('\n')
117+
.map((line) => ` * ${line}`)
118+
.join('\n');
119+
}
120+
114121
if (line.includes('PARAMETER')) {
115122
return vars.map((name) => ` * @param {string} ${name}`).join('\n');
116123
}
117124

118125
return line;
119126
})
127+
.filter((x) => x !== '')
120128
.join('\n');
121129

122130
if (value !== node.value) {
@@ -168,7 +176,7 @@ function transform(name, dest) {
168176
for (let i = 0; i < parts.length; i += 1) {
169177
const part = parts[i];
170178
if (i % 2 === 0) {
171-
const str = part.replace(/(`|\$)/g, '\\$1');
179+
const str = part.replace(/(`|\${)/g, '\\$1');
172180
quasis.push({
173181
type: 'TemplateElement',
174182
value: { raw: str, cooked: str },
@@ -211,3 +219,4 @@ function transform(name, dest) {
211219
}
212220

213221
transform('compile-errors', 'src/compiler/errors.js');
222+
transform('compile-warnings', 'src/compiler/warnings.js');

packages/svelte/scripts/process-messages/templates/compile-errors.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ export class CompileError extends Error {
4747
}
4848

4949
/**
50-
*
5150
* @param {null | number | NodeLike} node
5251
* @param {string} code
5352
* @param {string} message
@@ -65,6 +64,7 @@ function e(node, code, message) {
6564
}
6665

6766
/**
67+
* MESSAGE
6868
* @param {null | number | NodeLike} node
6969
* @param {string} PARAMETER
7070
* @returns {never}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { getLocator } from 'locate-character';
2+
3+
/** @typedef {{ start?: number, end?: number }} NodeLike */
4+
5+
/** @type {import('#compiler').Warning[]} */
6+
let warnings = [];
7+
8+
/** @type {string | undefined} */
9+
let filename;
10+
11+
let locator = getLocator('', { offsetLine: 1 });
12+
13+
/**
14+
* @param {{
15+
* source: string;
16+
* filename: string | undefined;
17+
* }} options
18+
* @returns {import('#compiler').Warning[]}
19+
*/
20+
export function reset_warnings(options) {
21+
filename = options.filename;
22+
locator = getLocator(options.source, { offsetLine: 1 });
23+
24+
return (warnings = []);
25+
}
26+
27+
/**
28+
* @param {null | NodeLike} node
29+
* @param {string} code
30+
* @param {string} message
31+
*/
32+
function w(node, code, message) {
33+
// @ts-expect-error
34+
if (node.ignores?.has(code)) return;
35+
36+
warnings.push({
37+
code,
38+
message,
39+
filename,
40+
start: node?.start !== undefined ? locator(node.start) : undefined,
41+
end: node?.end !== undefined ? locator(node.end) : undefined
42+
});
43+
}
44+
45+
/**
46+
* MESSAGE
47+
* @param {null | NodeLike} node
48+
* @param {string} PARAMETER
49+
*/
50+
export function CODE(node, PARAMETER) {
51+
w(node, 'CODE', MESSAGE);
52+
}

0 commit comments

Comments
 (0)