warn on unknown attributes

pull/12948/head
Rich Harris 2 years ago
parent 6e1d998ca1
commit e72d679d3f

@ -54,6 +54,10 @@ This code will work when the component is rendered on the client (which is why t
> `context="module"` is deprecated, use the `module` attribute instead
## script_unknown_attribute
> Unrecognized attribute — should be one of `generics`, `lang` or `module`. If this exists for a preprocessor, ensure that the preprocessor removes it
## slot_element_deprecated
> Using `<slot>` to render parent content is deprecated. Use `{@render ...}` tags instead

@ -1052,6 +1052,15 @@ export function script_duplicate(node) {
e(node, "script_duplicate", "A component can have a single top-level `<script>` element and/or a single top-level `<script module>` element");
}
/**
* A top-level `<script>` element can only have static attributes
* @param {null | number | NodeLike} node
* @returns {never}
*/
export function script_invalid_attribute(node) {
e(node, "script_invalid_attribute", "A top-level `<script>` element can only have static attributes");
}
/**
* If the `%name%` attribute is supplied, it must be a boolean attribute
* @param {null | number | NodeLike} node

@ -5,52 +5,13 @@ import * as acorn from '../acorn.js';
import { regex_not_newline_characters } from '../../patterns.js';
import * as e from '../../../errors.js';
import * as w from '../../../warnings.js';
import { is_text_attribute } from '../../../utils/ast.js';
const regex_closing_script_tag = /<\/script\s*>/;
const regex_starts_with_closing_script_tag = /^<\/script\s*>/;
/**
* @param {any[]} attributes
* @returns {string}
*/
function get_context(attributes) {
for (const attribute of attributes) {
switch (attribute.name) {
case 'context': {
if (attribute.value.length !== 1 || attribute.value[0].type !== 'Text') {
e.script_invalid_context(attribute.start);
}
const value = attribute.value[0].data;
if (value !== 'module') {
e.script_invalid_context(attribute.start);
}
w.script_context_deprecated(attribute);
return value;
}
case 'module': {
if (attribute.value !== true) {
// Deliberately a generic code to future-proof for potential other attributes
e.script_invalid_attribute_value(attribute.start, attribute.name);
}
return 'module';
}
case 'server':
case 'client':
case 'worker':
case 'test':
case 'default': {
e.script_reserved_attribute(attribute.start, attribute.name);
}
}
}
return 'default';
}
const RESERVED_ATTRIBUTES = ['server', 'client', 'worker', 'test', 'default'];
const ALLOWED_ATTRIBUTES = ['context', 'generics', 'lang', 'module'];
/**
* @param {Parser} parser
@ -81,14 +42,56 @@ export function read_script(parser, start, attributes) {
// TODO is this necessary?
ast.start = script_start;
/** @type {'default' | 'module'} */
let context = 'default';
for (const attribute of /** @type {Attribute[]} */ (attributes)) {
if (RESERVED_ATTRIBUTES.includes(attribute.name)) {
e.script_reserved_attribute(attribute, attribute.name);
}
if (!ALLOWED_ATTRIBUTES.includes(attribute.name)) {
w.script_unknown_attribute(attribute);
}
if (attribute.name === 'module') {
if (attribute.value !== true) {
// Deliberately a generic code to future-proof for potential other attributes
e.script_invalid_attribute_value(attribute, attribute.name);
}
context = 'module';
}
if (attribute.name === 'context') {
if (attribute.value === true || !is_text_attribute(attribute)) {
throw new Error('TODO');
}
if (attribute.value.length !== 1 || attribute.value[0].type !== 'Text') {
e.script_invalid_context(attribute);
}
const value = attribute.value[0].data;
if (value !== 'module') {
e.script_invalid_context(attribute);
}
w.script_context_deprecated(attribute);
context = 'module';
}
}
return {
type: 'Script',
start,
end: parser.index,
context: get_context(attributes),
context,
content: ast,
parent: null,
// @ts-ignore
attributes: attributes
attributes
};
}

@ -488,7 +488,7 @@ export type SvelteNode = Node | TemplateNode | Fragment | Css.Node;
export interface Script extends BaseNode {
type: 'Script';
context: string;
context: 'default' | 'module';
content: Program;
attributes: Attribute[];
}

@ -118,6 +118,7 @@ export const codes = [
"event_directive_deprecated",
"node_invalid_placement_ssr",
"script_context_deprecated",
"script_unknown_attribute",
"slot_element_deprecated",
"svelte_component_deprecated",
"svelte_element_invalid_this"
@ -778,6 +779,14 @@ export function script_context_deprecated(node) {
w(node, "script_context_deprecated", "`context=\"module\"` is deprecated, use the `module` attribute instead");
}
/**
* Unrecognized attribute should be one of `generics`, `lang` or `module`. If this exists for a preprocessor, ensure that the preprocessor removes it
* @param {null | NodeLike} node
*/
export function script_unknown_attribute(node) {
w(node, "script_unknown_attribute", "Unrecognized attribute — should be one of `generics`, `lang` or `module`. If this exists for a preprocessor, ensure that the preprocessor removes it");
}
/**
* Using `<slot>` to render parent content is deprecated. Use `{@render ...}` tags instead
* @param {null | NodeLike} node

@ -8,7 +8,7 @@
},
"end": {
"line": 1,
"column": 8
"column": 22
}
}
]

@ -0,0 +1,14 @@
[
{
"code": "script_unknown_attribute",
"message": "Unrecognized attribute — should be one of `generics`, `lang` or `module`. If this exists for a preprocessor, ensure that the preprocessor removes it",
"start": {
"column": 8,
"line": 1
},
"end": {
"column": 18,
"line": 1
}
}
]

@ -0,0 +1,14 @@
[
{
"code": "script_unknown_attribute",
"message": "Unrecognized attribute — should be one of `generics`, `lang` or `module`. If this exists for a preprocessor, ensure that the preprocessor removes it",
"start": {
"column": 8,
"line": 1
},
"end": {
"column": 14,
"line": 1
}
}
]
Loading…
Cancel
Save