From f0b2cb99f2e91a0bc033c313b170cf1e65f65d65 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 14 Apr 2018 21:38:37 -0400 Subject: [PATCH 1/4] add codes to warnings (#474) --- src/css/Stylesheet.ts | 1 + src/generators/wrapModule.ts | 1 + src/interfaces.ts | 1 + src/validate/html/a11y.ts | 80 +++++++++++++++---- src/validate/html/index.ts | 13 +-- src/validate/html/validateElement.ts | 13 +-- src/validate/html/validateEventHandler.ts | 13 +-- src/validate/index.ts | 12 +-- src/validate/js/propValidators/components.ts | 5 +- src/validate/js/propValidators/helpers.ts | 8 +- src/validate/js/propValidators/onrender.ts | 11 +-- src/validate/js/propValidators/onteardown.ts | 11 +-- .../omit-scoping-element-uppercase/_config.js | 1 + test/validator/index.js | 13 +-- .../samples/a11y-alt-text/warnings.json | 4 + .../a11y-anchor-has-content/warnings.json | 1 + .../a11y-anchor-in-svg-is-valid/warnings.json | 3 + .../a11y-anchor-is-valid/warnings.json | 3 + .../samples/a11y-aria-props/warnings.json | 2 + .../samples/a11y-aria-role/warnings.json | 1 + .../warnings.json | 2 + .../a11y-figcaption-wrong-place/warnings.json | 2 + .../a11y-heading-has-content/warnings.json | 2 + .../samples/a11y-html-has-lang/warnings.json | 3 +- .../a11y-iframe-has-title/warnings.json | 1 + .../samples/a11y-no-access-key/warnings.json | 1 + .../samples/a11y-no-autofocus/warnings.json | 1 + .../warnings.json | 2 + .../a11y-not-on-components/warnings.json | 1 + .../samples/a11y-scope/warnings.json | 1 + .../a11y-tabindex-no-positive/warnings.json | 1 + .../samples/empty-block-dev/warnings.json | 2 + .../helper-clash-context/warnings.json | 1 + .../warnings.json | 1 + .../method-nonexistent-helper/warnings.json | 1 + .../samples/method-nonexistent/warnings.json | 1 + .../samples/missing-component/warnings.json | 1 + .../warnings.json | 1 + .../samples/store-unexpected/warnings.json | 1 + .../warnings.json | 5 ++ .../samples/unused-components/warnings.json | 2 + .../samples/unused-event/warnings.json | 1 + .../samples/unused-transition/warnings.json | 1 + .../window-event-invalid/warnings.json | 1 + 44 files changed, 175 insertions(+), 58 deletions(-) diff --git a/src/css/Stylesheet.ts b/src/css/Stylesheet.ts index 00233b80c9..464dbd2500 100644 --- a/src/css/Stylesheet.ts +++ b/src/css/Stylesheet.ts @@ -435,6 +435,7 @@ export default class Stylesheet { const message = `Unused CSS selector`; onwarn({ + code: `css-unused-selector`, message, frame, loc: { line: line + 1, column }, diff --git a/src/generators/wrapModule.ts b/src/generators/wrapModule.ts index cdc9db2513..38e837692f 100644 --- a/src/generators/wrapModule.ts +++ b/src/generators/wrapModule.ts @@ -276,6 +276,7 @@ function getGlobals(dependencies: Dependency[], options: CompileOptions) { onerror(error); } else { const warning = { + code: `options-missing-globals`, message: `No name was supplied for imported module '${d.source}'. Guessing '${d.name}', but you should use options.globals`, }; diff --git a/src/interfaces.ts b/src/interfaces.ts index dc3fb614c1..dfce819d5e 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -31,6 +31,7 @@ export interface Warning { loc?: { line: number; column: number; pos?: number }; end?: { line: number; column: number; }; pos?: number; + code: string; message: string; filename?: string; frame?: string; diff --git a/src/validate/html/a11y.ts b/src/validate/html/a11y.ts index c52180cf63..bb264326d0 100644 --- a/src/validate/html/a11y.ts +++ b/src/validate/html/a11y.ts @@ -35,7 +35,10 @@ export default function a11y( if (name.startsWith('aria-')) { if (invisibleElements.has(node.name)) { // aria-unsupported-elements - validator.warn(`A11y: <${node.name}> should not have aria-* attributes`, attribute); + validator.warn(attribute, { + code: `a11y-aria-attributes`, + message: `A11y: <${node.name}> should not have aria-* attributes` + }); } const type = name.slice(5); @@ -44,7 +47,10 @@ export default function a11y( let message = `A11y: Unknown aria attribute 'aria-${type}'`; if (match) message += ` (did you mean '${match}'?)`; - validator.warn(message, attribute); + validator.warn(attribute, { + code: `a11y-unknown-aria-attribute`, + message + }); } } @@ -52,7 +58,10 @@ export default function a11y( if (name === 'role') { if (invisibleElements.has(node.name)) { // aria-unsupported-elements - validator.warn(`A11y: <${node.name}> should not have role attribute`, attribute); + validator.warn(attribute, { + code: `a11y-misplaced-role`, + message: `A11y: <${node.name}> should not have role attribute` + }); } const value = getStaticAttributeValue(node, 'role'); @@ -61,30 +70,45 @@ export default function a11y( let message = `A11y: Unknown role '${value}'`; if (match) message += ` (did you mean '${match}'?)`; - validator.warn(message, attribute); + validator.warn(attribute, { + code: `a11y-unknown-role`, + message + }); } } // no-access-key if (name === 'accesskey') { - validator.warn(`A11y: Avoid using accesskey`, attribute); + validator.warn(attribute, { + code: `a11y-accesskey`, + message: `A11y: Avoid using accesskey` + }); } // no-autofocus if (name === 'autofocus') { - validator.warn(`A11y: Avoid using autofocus`, attribute); + validator.warn(attribute, { + code: `a11y-autofocus`, + message: `A11y: Avoid using autofocus` + }); } // scope if (name === 'scope' && node.name !== 'th') { - validator.warn(`A11y: The scope attribute should only be used with elements`, attribute); + validator.warn(attribute, { + code: `a11y-misplaced-scope`, + message: `A11y: The scope attribute should only be used with elements` + }); } // tabindex-no-positive if (name === 'tabindex') { const value = getStaticAttributeValue(node, 'tabindex'); if (!isNaN(value) && +value > 0) { - validator.warn(`A11y: avoid tabindex values above zero`, attribute); + validator.warn(attribute, { + code: `a11y-positive-tabindex`, + message: `A11y: avoid tabindex values above zero` + }); } } @@ -98,13 +122,19 @@ export default function a11y( attributes.slice(0, -1).join(', ') + ` or ${attributes[attributes.length - 1]}` : attributes[0]; - validator.warn(`A11y: <${name}> element should have ${article} ${sequence} attribute`, node); + validator.warn(node, { + code: `a11y-missing-attribute`, + message: `A11y: <${name}> element should have ${article} ${sequence} attribute` + }); } } function shouldHaveContent() { if (node.children.length === 0) { - validator.warn(`A11y: <${node.name}> element should have child content`, node); + validator.warn(node, { + code: `a11y-missing-content`, + message: `A11y: <${node.name}> element should have child content` + }); } } @@ -112,7 +142,10 @@ export default function a11y( const href = attributeMap.get(attribute); const value = getStaticAttributeValue(node, attribute); if (value === '' || value === '#') { - validator.warn(`A11y: '${value}' is not a valid ${attribute} attribute`, href); + validator.warn(href, { + code: `a11y-invalid-attribute`, + message: `A11y: '${value}' is not a valid ${attribute} attribute` + }); } } @@ -124,7 +157,10 @@ export default function a11y( // anchor-in-svg-is-valid shouldHaveValidHref('xlink:href') } else { - validator.warn(`A11y: element should have an href attribute`, node); + validator.warn(node, { + code: `a11y-missing-attribute`, + message: `A11y: element should have an href attribute` + }); } // anchor-has-content @@ -143,7 +179,10 @@ export default function a11y( shouldHaveContent(); if (attributeMap.has('aria-hidden')) { - validator.warn(`A11y: <${node.name}> element should not be hidden`, attributeMap.get('aria-hidden')); + validator.warn(attributeMap.get('aria-hidden'), { + code: `a11y-hidden`, + message: `A11y: <${node.name}> element should not be hidden` + }); } } @@ -159,14 +198,20 @@ export default function a11y( // no-distracting-elements if (node.name === 'marquee' || node.name === 'blink') { - validator.warn(`A11y: Avoid <${node.name}> elements`, node); + validator.warn(node, { + code: `a11y-distracting-elements`, + message: `A11y: Avoid <${node.name}> elements` + }); } if (node.name === 'figcaption') { const parent = elementStack[elementStack.length - 1]; if (parent) { if (parent.name !== 'figure') { - validator.warn(`A11y:
must be an immediate child of
`, node); + validator.warn(node, { + code: `a11y-structure`, + message: `A11y:
must be an immediate child of
` + }); } else { const children = parent.children.filter(node => { if (node.type === 'Comment') return false; @@ -177,7 +222,10 @@ export default function a11y( const index = children.indexOf(node); if (index !== 0 && index !== children.length - 1) { - validator.warn(`A11y:
must be first or last child of
`, node); + validator.warn(node, { + code: `a11y-structure`, + message: `A11y:
must be first or last child of
` + }); } } } diff --git a/src/validate/html/index.ts b/src/validate/html/index.ts index 6e2b6b4133..87291b7279 100644 --- a/src/validate/html/index.ts +++ b/src/validate/html/index.ts @@ -61,15 +61,18 @@ export default function validateHtml(validator: Validator, html: Node) { c += 2; while (/\s/.test(validator.source[c])) c += 1; - validator.warn( - `Context clashes with a helper. Rename one or the other to eliminate any ambiguity`, - { start: c, end: c + node.context.length } - ); + validator.warn({ start: c, end: c + node.context.length }, { + code: `each-context-clash`, + message: `Context clashes with a helper. Rename one or the other to eliminate any ambiguity` + }); } } if (validator.options.dev && isEmptyBlock(node)) { - validator.warn('Empty block', node); + validator.warn(node, { + code: `empty-block`, + message: 'Empty block' + }); } if (node.children) { diff --git a/src/validate/html/validateElement.ts b/src/validate/html/validateElement.ts index 473ccf545d..e5fdd0e94b 100644 --- a/src/validate/html/validateElement.ts +++ b/src/validate/html/validateElement.ts @@ -20,14 +20,17 @@ export default function validateElement( if (!isComponent && /^[A-Z]/.test(node.name[0])) { // TODO upgrade to validator.error in v2 - validator.warn(`${node.name} component is not defined`, node); + validator.warn(node, { + code: `missing-component`, + message: `${node.name} component is not defined` + }); } if (elementStack.length === 0 && validator.namespace !== namespaces.svg && svg.test(node.name)) { - validator.warn( - `<${node.name}> is an SVG element – did you forget to add { namespace: 'svg' } ?`, - node - ); + validator.warn(node, { + code: `missing-namespace`, + message: `<${node.name}> is an SVG element – did you forget to add { namespace: 'svg' } ?` + }); } if (node.name === 'slot') { diff --git a/src/validate/html/validateEventHandler.ts b/src/validate/html/validateEventHandler.ts index bbe0ec626a..4cbe8db08c 100644 --- a/src/validate/html/validateEventHandler.ts +++ b/src/validate/html/validateEventHandler.ts @@ -30,10 +30,10 @@ export default function validateEventHandlerCallee( if (name === 'store' && attribute.expression.callee.type === 'MemberExpression') { if (!validator.options.store) { - validator.warn( - 'compile with `store: true` in order to call store methods', - attribute.expression - ); + validator.warn(attribute.expression, { + code: `options-missing-store`, + message: 'compile with `store: true` in order to call store methods' + }); } return; } @@ -59,5 +59,8 @@ export default function validateEventHandlerCallee( message += `. '${callee.name}' exists on 'helpers', did you put it in the wrong place?`; } - validator.warn(message, attribute.expression); + validator.warn(attribute.expression, { + code: `invalid-callee`, + message + }); } diff --git a/src/validate/index.ts b/src/validate/index.ts index dd04eaa58a..796d2d28f9 100644 --- a/src/validate/index.ts +++ b/src/validate/index.ts @@ -69,7 +69,7 @@ export class Validator { }); } - warn(message: string, pos: { start: number, end: number }) { + warn(pos: { start: number, end: number }, { code, message }: { code: string, message: string }) { if (!this.locator) this.locator = getLocator(this.source); const start = this.locator(pos.start); const end = this.locator(pos.end); @@ -77,6 +77,7 @@ export class Validator { const frame = getCodeFrame(this.source, start.line, start.column); this.onwarn({ + code, message, frame, loc: { line: start.line + 1, column: start.column }, @@ -105,6 +106,7 @@ export default function validate( if (name && /^[a-z]/.test(name)) { const message = `options.name should be capitalised`; onwarn({ + code: `options-lowercase-name`, message, filename, toString: () => message, @@ -148,10 +150,10 @@ export default function validate( definitions.value.properties.forEach(prop => { const { name } = prop.key; if (!validator.used[category].has(name)) { - validator.warn( - `The '${name}' ${categories[category]} is unused`, - prop - ); + validator.warn(prop, { + code: `unused-${category.slice(0, -1)}`, + message: `The '${name}' ${categories[category]} is unused` + }); } }); } diff --git a/src/validate/js/propValidators/components.ts b/src/validate/js/propValidators/components.ts index 814b5c2142..4d695063f6 100644 --- a/src/validate/js/propValidators/components.ts +++ b/src/validate/js/propValidators/components.ts @@ -26,7 +26,10 @@ export default function components(validator: Validator, prop: Node) { } if (!/^[A-Z]/.test(name)) { - validator.warn(`Component names should be capitalised`, component); + validator.warn(component, { + code: `component-lowercase`, + message: `Component names should be capitalised` + }); } }); } diff --git a/src/validate/js/propValidators/helpers.ts b/src/validate/js/propValidators/helpers.ts index 20b32daca0..38b9467e6e 100644 --- a/src/validate/js/propValidators/helpers.ts +++ b/src/validate/js/propValidators/helpers.ts @@ -41,10 +41,10 @@ export default function helpers(validator: Validator, prop: Node) { }); if (prop.value.params.length === 0 && !usesArguments) { - validator.warn( - `Helpers should be pure functions, with at least one argument`, - prop - ); + validator.warn(prop, { + code: `impure-helper`, + message: `Helpers should be pure functions, with at least one argument` + }); } }); } diff --git a/src/validate/js/propValidators/onrender.ts b/src/validate/js/propValidators/onrender.ts index a3dd00d78c..23b07823c5 100644 --- a/src/validate/js/propValidators/onrender.ts +++ b/src/validate/js/propValidators/onrender.ts @@ -1,11 +1,12 @@ import oncreate from './oncreate'; -import { Validator } from '../../'; +import { Validator } from '../../index'; import { Node } from '../../../interfaces'; export default function onrender(validator: Validator, prop: Node) { - validator.warn( - `'onrender' has been deprecated in favour of 'oncreate', and will cause an error in Svelte 2.x`, - prop - ); + validator.warn(prop, { + code: `deprecated-onrender`, + message: `'onrender' has been deprecated in favour of 'oncreate', and will cause an error in Svelte 2.x` + }); + oncreate(validator, prop); } diff --git a/src/validate/js/propValidators/onteardown.ts b/src/validate/js/propValidators/onteardown.ts index f69df302c2..fe4e3a67b1 100644 --- a/src/validate/js/propValidators/onteardown.ts +++ b/src/validate/js/propValidators/onteardown.ts @@ -1,11 +1,12 @@ import ondestroy from './ondestroy'; -import { Validator } from '../../'; +import { Validator } from '../../index'; import { Node } from '../../../interfaces'; export default function onteardown(validator: Validator, prop: Node) { - validator.warn( - `'onteardown' has been deprecated in favour of 'ondestroy', and will cause an error in Svelte 2.x`, - prop - ); + validator.warn(prop, { + code: `deprecated-onteardown`, + message: `'onteardown' has been deprecated in favour of 'ondestroy', and will cause an error in Svelte 2.x` + }); + ondestroy(validator, prop); } diff --git a/test/css/samples/omit-scoping-element-uppercase/_config.js b/test/css/samples/omit-scoping-element-uppercase/_config.js index 8ade4401cf..aba09bb780 100644 --- a/test/css/samples/omit-scoping-element-uppercase/_config.js +++ b/test/css/samples/omit-scoping-element-uppercase/_config.js @@ -2,6 +2,7 @@ export default { cascade: false, warnings: [{ + code: 'missing-component', message: 'P component is not defined', loc: { line: 2, diff --git a/test/validator/index.js b/test/validator/index.js index 0ea1120493..211c763f48 100644 --- a/test/validator/index.js +++ b/test/validator/index.js @@ -25,12 +25,8 @@ describe("validate", () => { const { stats } = svelte.compile(input, { onwarn(warning) { - warnings.push({ - message: warning.message, - pos: warning.pos, - loc: warning.loc, - end: warning.end, - }); + const { code, message, pos, loc, end } = warning; + warnings.push({ code, message, pos, loc, end }); }, dev: config.dev }); @@ -39,6 +35,7 @@ describe("validate", () => { stats.warnings.forEach((full, i) => { const lite = warnings[i]; assert.deepEqual({ + code: full.code, message: full.message, pos: full.pos, loc: full.loc, @@ -62,6 +59,7 @@ describe("validate", () => { throw new Error(`Expected an error: ${expected.message}`); } + assert.equal(error.code, expected.code); assert.equal(error.message, expected.message); assert.deepEqual(error.loc, expected.loc); assert.deepEqual(error.end, expected.end); @@ -100,6 +98,7 @@ describe("validate", () => { name: "lowercase", onwarn(warning) { warnings.push({ + code: warning.code, message: warning.message, pos: warning.pos, loc: warning.loc @@ -108,6 +107,7 @@ describe("validate", () => { }); assert.deepEqual(warnings, [ { + code: `options-lowercase-name`, message: "options.name should be capitalised", pos: undefined, loc: undefined @@ -121,6 +121,7 @@ describe("validate", () => { name: "_", onwarn(warning) { warnings.push({ + code: warning.code, message: warning.message, pos: warning.pos, loc: warning.loc diff --git a/test/validator/samples/a11y-alt-text/warnings.json b/test/validator/samples/a11y-alt-text/warnings.json index dd5d319884..ec54e281e7 100644 --- a/test/validator/samples/a11y-alt-text/warnings.json +++ b/test/validator/samples/a11y-alt-text/warnings.json @@ -1,5 +1,6 @@ [ { + "code": "a11y-missing-attribute", "message": "A11y: element should have an alt attribute", "loc": { "line": 1, @@ -13,6 +14,7 @@ }, { + "code": "a11y-missing-attribute", "message": "A11y: element should have an alt, aria-label or aria-labelledby attribute", "loc": { "line": 4, @@ -26,6 +28,7 @@ }, { + "code": "a11y-missing-attribute", "message": "A11y: element should have a title, aria-label or aria-labelledby attribute", "loc": { "line": 7, @@ -39,6 +42,7 @@ }, { + "code": "a11y-missing-attribute", "message": "A11y: element should have an alt, aria-label or aria-labelledby attribute", "loc": { "line": 9, diff --git a/test/validator/samples/a11y-anchor-has-content/warnings.json b/test/validator/samples/a11y-anchor-has-content/warnings.json index ed8f6ad454..151fb6cd32 100644 --- a/test/validator/samples/a11y-anchor-has-content/warnings.json +++ b/test/validator/samples/a11y-anchor-has-content/warnings.json @@ -1,4 +1,5 @@ [{ + "code": "a11y-missing-content", "message": "A11y: element should have child content", "loc": { "line": 1, diff --git a/test/validator/samples/a11y-anchor-in-svg-is-valid/warnings.json b/test/validator/samples/a11y-anchor-in-svg-is-valid/warnings.json index fac62f3e13..a5533b5971 100644 --- a/test/validator/samples/a11y-anchor-in-svg-is-valid/warnings.json +++ b/test/validator/samples/a11y-anchor-in-svg-is-valid/warnings.json @@ -1,5 +1,6 @@ [ { + "code": "a11y-missing-attribute", "message": "A11y: element should have an href attribute", "loc": { "line": 1, @@ -12,6 +13,7 @@ "pos": 11 }, { + "code": "a11y-invalid-attribute", "message": "A11y: '' is not a valid xlink:href attribute", "loc": { "line": 2, @@ -24,6 +26,7 @@ "pos": 65 }, { + "code": "a11y-invalid-attribute", "message": "A11y: '#' is not a valid xlink:href attribute", "loc": { "line": 3, diff --git a/test/validator/samples/a11y-anchor-is-valid/warnings.json b/test/validator/samples/a11y-anchor-is-valid/warnings.json index 86135b84c9..70ea534a4b 100644 --- a/test/validator/samples/a11y-anchor-is-valid/warnings.json +++ b/test/validator/samples/a11y-anchor-is-valid/warnings.json @@ -1,5 +1,6 @@ [ { + "code": "a11y-missing-attribute", "message": "A11y: element should have an href attribute", "loc": { "line": 1, @@ -12,6 +13,7 @@ "pos": 0 }, { + "code": "a11y-invalid-attribute", "message": "A11y: '' is not a valid href attribute", "loc": { "line": 2, @@ -24,6 +26,7 @@ "pos": 30 }, { + "code": "a11y-invalid-attribute", "message": "A11y: '#' is not a valid href attribute", "loc": { "line": 3, diff --git a/test/validator/samples/a11y-aria-props/warnings.json b/test/validator/samples/a11y-aria-props/warnings.json index 7f2880dc34..4eb6815fe1 100644 --- a/test/validator/samples/a11y-aria-props/warnings.json +++ b/test/validator/samples/a11y-aria-props/warnings.json @@ -1,5 +1,6 @@ [ { + "code": "a11y-unknown-aria-attribute", "message": "A11y: Unknown aria attribute 'aria-labeledby' (did you mean 'labelledby'?)", "loc": { "line": 1, @@ -13,6 +14,7 @@ }, { + "code": "a11y-missing-attribute", "message": "A11y: element should have an alt, aria-label or aria-labelledby attribute", "loc": { "column": 0, diff --git a/test/validator/samples/a11y-aria-role/warnings.json b/test/validator/samples/a11y-aria-role/warnings.json index 903381b295..425f790dd7 100644 --- a/test/validator/samples/a11y-aria-role/warnings.json +++ b/test/validator/samples/a11y-aria-role/warnings.json @@ -1,5 +1,6 @@ [ { + "code": "a11y-unknown-role", "message": "A11y: Unknown role 'toooltip' (did you mean 'tooltip'?)", "loc": { "line": 1, diff --git a/test/validator/samples/a11y-aria-unsupported-element/warnings.json b/test/validator/samples/a11y-aria-unsupported-element/warnings.json index 369b81278c..f837b13178 100644 --- a/test/validator/samples/a11y-aria-unsupported-element/warnings.json +++ b/test/validator/samples/a11y-aria-unsupported-element/warnings.json @@ -1,5 +1,6 @@ [ { + "code": "a11y-aria-attributes", "message": "A11y: should not have aria-* attributes", "loc": { "line": 1, @@ -13,6 +14,7 @@ }, { + "code": "a11y-misplaced-role", "message": "A11y: should not have role attribute", "loc": { "line": 2, diff --git a/test/validator/samples/a11y-figcaption-wrong-place/warnings.json b/test/validator/samples/a11y-figcaption-wrong-place/warnings.json index ed1edb3f8c..dc09be6ad7 100644 --- a/test/validator/samples/a11y-figcaption-wrong-place/warnings.json +++ b/test/validator/samples/a11y-figcaption-wrong-place/warnings.json @@ -1,5 +1,6 @@ [ { + "code": "a11y-structure", "message": "A11y:
must be first or last child of
", "loc": { "line": 4, @@ -12,6 +13,7 @@ "pos": 57 }, { + "code": "a11y-structure", "message": "A11y:
must be an immediate child of
", "loc": { "line": 15, diff --git a/test/validator/samples/a11y-heading-has-content/warnings.json b/test/validator/samples/a11y-heading-has-content/warnings.json index c269dd9e4b..a785116866 100644 --- a/test/validator/samples/a11y-heading-has-content/warnings.json +++ b/test/validator/samples/a11y-heading-has-content/warnings.json @@ -1,5 +1,6 @@ [ { + "code": "a11y-missing-content", "message": "A11y:

element should have child content", "loc": { "line": 1, @@ -13,6 +14,7 @@ }, { + "code": "a11y-hidden", "message": "A11y:

element should not be hidden", "loc": { "line": 2, diff --git a/test/validator/samples/a11y-html-has-lang/warnings.json b/test/validator/samples/a11y-html-has-lang/warnings.json index 26afa41fa9..c8c7c51cc6 100644 --- a/test/validator/samples/a11y-html-has-lang/warnings.json +++ b/test/validator/samples/a11y-html-has-lang/warnings.json @@ -1,5 +1,7 @@ [ { + "code": "a11y-missing-attribute", + "message": "A11y: element should have a lang attribute", "loc": { "column": 0, "line": 5 @@ -8,7 +10,6 @@ "line": 5, "column": 13 }, - "message": "A11y: element should have a lang attribute", "pos": 84 } ] diff --git a/test/validator/samples/a11y-iframe-has-title/warnings.json b/test/validator/samples/a11y-iframe-has-title/warnings.json index 3d38672b76..33706158df 100644 --- a/test/validator/samples/a11y-iframe-has-title/warnings.json +++ b/test/validator/samples/a11y-iframe-has-title/warnings.json @@ -1,5 +1,6 @@ [ { + "code": "a11y-missing-attribute", "message": "A11y: