...
 
Commits (39)
{
"env": {
"node": true
},
"extends": [
"@html-validate",
"plugin:array-func/recommended",
"plugin:node/recommended-module",
"plugin:security/recommended",
"plugin:sonarjs/recommended"
],
"plugins": ["array-func", "node", "security", "sonarjs"],
"extends": ["@html-validate", "plugin:security/recommended", "plugin:sonarjs/recommended"],
"plugins": ["security", "sonarjs"],
"rules": {
"import/named": "off",
"node/no-missing-import": "off",
"node/no-unsupported-features/es-syntax": "off",
"security/detect-non-literal-fs-filename": "off",
"security/detect-non-literal-require": "off",
......@@ -38,7 +26,8 @@
"extends": ["@html-validate/eslint-config/jest"],
"rules": {
"sonarjs/no-duplicate-string": "off",
"sonarjs/no-identical-functions": "off"
"sonarjs/no-identical-functions": "off",
"@typescript-eslint/no-non-null-assertion": "off"
}
}
]
......
# Remember to keep in sync with .npmignore
/*.tgz
*.tgz
/.nyc_output/
/.tscache/
/dist
......
......@@ -29,9 +29,9 @@ Build:
paths:
- dist/
script:
- npm run build
- npm run --if-present build
- npm pack
- npx npm-pkg-lint
- npm exec npm-pkg-lint
pages:
stage: build
......@@ -42,7 +42,7 @@ pages:
- tags
- triggers
script:
- npm run build
- npm run --if-present build
- npm run build:docs
Changelog:
......@@ -62,7 +62,7 @@ Jest:
stage: test
dependencies: ["NPM"]
needs: ["NPM"]
coverage: /Lines\s+:\s(\d+.\d+%)/
coverage: /Branches\s+:\s(\d+.\d+%)/
artifacts:
name: ${CI_PROJECT_PATH_SLUG}-${CI_PIPELINE_ID}-coverage
paths:
......@@ -99,7 +99,7 @@ Docs:
- npm ci
script:
- npm test
- npm run build
- npm run --if-present build
- npm run compatibility
Node 10.x (LTS):
......
......@@ -21,3 +21,4 @@
# local test files
/sites
/test.html
# html-validate changelog
## [4.1.0](https://gitlab.com/html-validate/html-validate/compare/v4.0.2...v4.1.0) (2020-12-14)
### Features
- replace `inquirer` with `prompts` ([82d17eb](https://gitlab.com/html-validate/html-validate/commit/82d17ebce26d0e215fa689095fb2822ae541f2d8))
### [4.0.2](https://gitlab.com/html-validate/html-validate/compare/v4.0.1...v4.0.2) (2020-11-19)
### Bug Fixes
......
......@@ -22,45 +22,43 @@ module.exports = function parseValidatesProcessor(
return;
}
doc.content = doc.content.replace(VALIDATE_REGEX, function processValidate(
match,
attributeText,
validateMarkup
) {
const attr = extractAttributes(attributeText);
if (!attr.name) {
throw new Error(createDocMessage("Inline validation is missing name", doc));
}
const name = attr.name;
const rules = attr.rules ? attr.rules.split(/ +/) : undefined;
const showResults = attr.results ? Boolean(attr.results) : "auto";
const elements = readElements(doc.fileInfo, attr.elements);
const id = uniqueName(validateMap, `markup-${attr.name}`);
const markup = trimIndentation(validateMarkup);
const config = generateConfig(rules, elements, attr);
const validate = {
config,
name,
markup,
showResults,
id,
doc,
};
// store the validate information for later
log.debug("Storing inline validation", id);
validateMap.set(id, validate);
return `{@inlineValidation ${id}}`;
});
doc.content = doc.content.replace(VALIDATE_REGEX, processValidate.bind(undefined, doc));
} catch (error) {
throw new Error(createDocMessage("Failed to parse inline validation", doc, error));
}
});
}
function processValidate(doc, match, attributeText, validateMarkup) {
const attr = extractAttributes(attributeText);
if (!attr.name) {
throw new Error(createDocMessage("Inline validation is missing name", doc));
}
const name = attr.name;
const rules = attr.rules ? attr.rules.split(/ +/) : undefined;
const showResults = attr.results ? Boolean(attr.results) : "auto";
const elements = readElements(doc.fileInfo, attr.elements);
const id = uniqueName(validateMap, `markup-${attr.name}`);
const markup = trimIndentation(validateMarkup);
const config = generateConfig(rules, elements, attr);
const validate = {
config,
name,
markup,
showResults,
id,
doc,
};
// store the validate information for later
log.debug("Storing inline validation", id);
validateMap.set(id, validate);
return `{@inlineValidation ${id}}`;
}
function readElements(fileInfo, filename) {
if (!filename) return filename;
const dir = path.dirname(fileInfo.filePath);
......
This diff is collapsed.
{
"name": "html-validate",
"version": "4.0.2",
"version": "4.1.0",
"description": "html linter",
"keywords": [
"html",
......@@ -8,20 +8,17 @@
"validator",
"html-validate"
],
"author": "David Sveningsson <ext@sidvind.com>",
"license": "MIT",
"homepage": "https://html-validate.org",
"bugs": {
"url": "https://gitlab.com/html-validate/html-validate/issues/new"
},
"repository": {
"type": "git",
"url": "https://gitlab.com/html-validate/html-validate.git"
},
"bugs": {
"url": "https://gitlab.com/html-validate/html-validate/issues/new"
},
"license": "MIT",
"author": "David Sveningsson <ext@sidvind.com>",
"main": "dist/shim.js",
"engines": {
"node": ">= 10.0"
},
"bin": {
"html-validate": "bin/html-validate.js"
},
......@@ -41,44 +38,55 @@
"scripts": {
"build": "tsc",
"build:docs": "grunt docs",
"clean": "rm -rf build public",
"compatibility": "scripts/compatibility.sh",
"clean": "rm -rf dist public",
"commitlint": "commitlint",
"compatibility": "scripts/compatibility.sh",
"debug": "node --inspect ./node_modules/.bin/jest --runInBand --watch --no-coverage",
"eslint": "eslint --ext js,ts .",
"eslint:fix": "eslint --ext js,ts . --fix",
"htmlvalidate": "./bin/html-validate.js",
"prepare": "git config commit.template ./node_modules/@html-validate/commitlint-config/gitmessage",
"prettier:check": "prettier . --check",
"prettier:write": "prettier . --write",
"prepare": "scripts/prepare.sh",
"prettier:check": "prettier --check .",
"prettier:write": "prettier --write .",
"semantic-release": "semantic-release",
"start": "grunt connect",
"test": "jest --ci"
},
"commitlint": {
"extends": [
"@html-validate"
]
},
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
"pre-commit": "lint-staged",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
"pre-push": "./scripts/pre-push"
}
},
"commitlint": {
"extends": [
"@html-validate"
]
},
"lint-staged": {
"*.{ts,js,json,html,md,scss}": "prettier --write"
},
"prettier": "@html-validate/prettier-config",
"renovate": {
"extends": [
"@html-validate"
"jest": {
"collectCoverageFrom": [
"src/**/*.ts",
"!src/**/*.spec.ts",
"!src/**/index.ts",
"!src/shim.ts",
"!src/cli/html-validate.ts"
],
"preset": "@html-validate/jest-config",
"roots": [
"<rootDir>/docs",
"<rootDir>/elements",
"<rootDir>/src",
"<rootDir>/tests"
],
"snapshotSerializers": [
"pretty-format/build/plugins/ConvertAnsi"
]
},
"release": {
"extends": "@html-validate/semantic-release-config"
},
"dependencies": {
"@babel/code-frame": "^7.10.4",
"@html-validate/stylish": "1.0.0",
......@@ -89,19 +97,19 @@
"deepmerge": "^4.2.2",
"espree": "^7.3.0",
"glob": "^7.1.6",
"inquirer": "^7.3.3",
"json-merge-patch": "^1.0.1",
"minimist": "^1.2.5"
"minimist": "^1.2.5",
"prompts": "^2.0.0"
},
"devDependencies": {
"@babel/core": "7.12.3",
"@babel/preset-env": "7.12.1",
"@babel/core": "7.12.9",
"@babel/preset-env": "7.12.7",
"@commitlint/cli": "11.0.0",
"@html-validate/commitlint-config": "1.1.1",
"@html-validate/eslint-config": "2.1.1",
"@html-validate/jest-config": "1.0.34",
"@html-validate/eslint-config": "2.3.2",
"@html-validate/jest-config": "1.1.0",
"@html-validate/prettier-config": "1.1.0",
"@html-validate/semantic-release-config": "1.1.1",
"@html-validate/semantic-release-config": "1.1.2",
"@lodder/grunt-postcss": "3.0.0",
"@types/babel__code-frame": "7.0.2",
"@types/estree": "0.0.45",
......@@ -110,7 +118,8 @@
"@types/jest": "26.0.15",
"@types/json-merge-patch": "0.0.5",
"@types/minimist": "1.2.1",
"@types/node": "11.15.35",
"@types/node": "11.15.38",
"@types/prompts": "2.0.9",
"autoprefixer": "10.0.2",
"babelify": "10.0.0",
"bootstrap-sass": "3.4.1",
......@@ -119,9 +128,7 @@
"dgeni": "0.4.12",
"dgeni-front-matter": "2.0.3",
"dgeni-packages": "0.28.4",
"eslint": "7.13.0",
"eslint-plugin-array-func": "3.1.7",
"eslint-plugin-node": "11.1.0",
"eslint": "7.14.0",
"eslint-plugin-security": "1.4.0",
"eslint-plugin-sonarjs": "0.5.0",
"font-awesome": "4.7.0",
......@@ -132,44 +139,36 @@
"grunt-contrib-connect": "3.0.0",
"grunt-contrib-copy": "1.0.0",
"grunt-sass": "3.1.0",
"highlight.js": "10.3.2",
"highlight.js": "10.4.0",
"husky": "4.3.0",
"jest": "26.6.3",
"jest-diff": "26.6.2",
"jquery": "3.5.1",
"lint-staged": "10.5.1",
"lint-staged": "10.5.2",
"load-grunt-tasks": "5.1.0",
"marked": "1.2.4",
"marked": "1.2.5",
"minimatch": "3.0.4",
"npm-pkg-lint": "1.2.0",
"postcss": "8.1.7",
"prettier": "2.1.2",
"npm-pkg-lint": "1.3.0",
"postcss": "8.1.10",
"prettier": "2.2.0",
"pretty-format": "26.6.2",
"sass": "1.29.0",
"semantic-release": "17.2.3",
"semantic-release": "17.3.0",
"serve-static": "1.14.1",
"stringmap": "0.2.2",
"strip-ansi": "6.0.0",
"ts-jest": "26.4.4",
"typescript": "4.0.5"
"typescript": "4.1.2"
},
"jest": {
"preset": "@html-validate/jest-config",
"collectCoverageFrom": [
"src/**/*.ts",
"!src/**/*.spec.ts",
"!src/**/index.ts",
"!src/shim.ts",
"!src/cli/html-validate.ts"
],
"roots": [
"<rootDir>/docs",
"<rootDir>/elements",
"<rootDir>/src",
"<rootDir>/tests"
],
"snapshotSerializers": [
"pretty-format/build/plugins/ConvertAnsi"
"engines": {
"node": ">= 10.0"
},
"release": {
"extends": "@html-validate/semantic-release-config"
},
"renovate": {
"extends": [
"@html-validate"
]
}
}
#/bin/sh
echo "Configure git commit.template"
git config --local commit.template ./node_modules/@html-validate/commitlint-config/gitmessage
......@@ -3,11 +3,9 @@ const fs = {
writeFile: jest.fn().mockImplementation((fn, data, cb) => cb()),
};
const inquirer = {
prompt: jest.fn(),
};
const prompts = jest.fn();
jest.mock("inquirer", () => inquirer);
jest.mock("prompts", () => prompts);
jest.mock("fs", () => fs);
import { CLI } from "./cli";
......@@ -27,7 +25,7 @@ it.each([
])("should generate configuration for %s", async (name, frameworks) => {
expect.assertions(2);
fs.existsSync.mockReturnValue(false);
inquirer.prompt.mockResolvedValue({
prompts.mockResolvedValue({
write: true,
frameworks,
});
......@@ -43,8 +41,8 @@ it.each([
it("should not overwrite configuration unless requested", async () => {
expect.assertions(1);
fs.existsSync.mockReturnValue(true);
inquirer.prompt.mockResolvedValue({
write: false,
prompts.mockResolvedValue({
overwrite: false,
});
try {
await cli.init(".");
......@@ -54,11 +52,21 @@ it("should not overwrite configuration unless requested", async () => {
expect(fs.writeFile).not.toHaveBeenCalled();
});
it("should overwrite configuration when requested", async () => {
expect.assertions(1);
fs.existsSync.mockReturnValue(true);
prompts.mockResolvedValue({
overwrite: true,
frameworks: [],
});
await cli.init(".");
expect(fs.writeFile).toHaveBeenCalled();
});
it("should always create configuration when config is missing", async () => {
expect.assertions(1);
fs.existsSync.mockReturnValue(false);
inquirer.prompt.mockResolvedValue({
write: undefined,
prompts.mockResolvedValue({
frameworks: [],
});
await cli.init(".");
......@@ -73,8 +81,7 @@ it("should propagate errors from fs.writeFile", async () => {
expect.assertions(1);
fs.existsSync.mockReturnValue(false);
fs.writeFile.mockImplementationOnce((fn, data, cb) => cb("mock error"));
inquirer.prompt.mockResolvedValue({
write: true,
prompts.mockResolvedValue({
frameworks: [],
});
await expect(cli.init(".")).rejects.toEqual("mock error");
......
import fs from "fs";
import deepmerge from "deepmerge";
import inquirer from "inquirer";
import prompts from "prompts";
import { ConfigData } from "../config";
export interface InitResult {
......@@ -58,33 +58,34 @@ export async function init(cwd: string): Promise<InitResult> {
elements: ["html5"],
extends: ["html-validate:recommended"],
};
const when = /* istanbul ignore next */ (answers: any): boolean => {
return !exists || answers.write;
};
const questions: inquirer.QuestionCollection = [
{
name: "write",
/* confirm overwrite */
if (exists) {
const result = await prompts({
name: "overwrite",
type: "confirm",
default: false,
when: exists,
message: "A .htmlvalidate.json file already exists, do you want to overwrite it?",
},
});
if (!result.overwrite) {
return Promise.reject();
}
}
const questions: prompts.PromptObject[] = [
{
name: "frameworks",
type: "checkbox",
choices: [Frameworks.angularjs, Frameworks.vuejs, Frameworks.markdown],
type: "multiselect",
choices: [
{ title: Frameworks.angularjs, value: Frameworks.angularjs },
{ title: Frameworks.vuejs, value: Frameworks.vuejs },
{ title: Frameworks.markdown, value: Frameworks.markdown },
],
message: "Support additional frameworks?",
when,
},
];
/* prompt user for questions */
const answers = await inquirer.prompt(questions);
/* dont overwrite configuration unless explicitly requested */
if (exists && !answers.write) {
return Promise.reject();
}
const answers = await prompts(questions);
/* write configuration to file */
let config = initialConfig;
......
......@@ -5,7 +5,7 @@ export enum Combinator {
GENERAL_SIBLING,
}
export function parseCombinator(combinator: string): Combinator {
export function parseCombinator(combinator: string | undefined | null): Combinator {
switch (combinator) {
case undefined:
case null:
......
......@@ -25,7 +25,7 @@ export class DOMNode {
public readonly nodeType: NodeType;
public readonly childNodes: DOMNode[];
public readonly location: Location;
public readonly location: Location | null;
public readonly unique: DOMInternalID;
private readonly cache: Map<string | number | symbol, any>;
......@@ -45,7 +45,7 @@ export class DOMNode {
* to the tagName but other node types have specific predefined values.
* @param location - Source code location of this node.
*/
public constructor(nodeType: NodeType, nodeName: string, location?: Location) {
public constructor(nodeType: NodeType, nodeName: string, location: Location | null = null) {
this.nodeType = nodeType;
this.nodeName = nodeName || DOCUMENT_NODE_NAME;
this.location = location;
......
......@@ -45,7 +45,7 @@ export class DOMTokenList extends Array<string> {
public readonly value: string;
private readonly locations: Location[] | undefined;
public constructor(value: string | DynamicValue, location?: Location) {
public constructor(value: string | DynamicValue | null, location?: Location) {
if (value && typeof value === "string") {
const { tokens, locations } = parse(value, location);
super(...tokens);
......@@ -57,7 +57,7 @@ export class DOMTokenList extends Array<string> {
if (value instanceof DynamicValue) {
this.value = value.expr;
} else {
this.value = value;
this.value = value || "";
}
}
......
......@@ -7,7 +7,7 @@ export class DOMTree {
private active: HtmlElement;
public doctype?: string;
public constructor(location: Location) {
public constructor(location: Location | null) {
this.root = HtmlElement.rootNode(location);
this.active = this.root;
this.doctype = null;
......
......@@ -101,7 +101,7 @@ describe("HtmlElement", () => {
const open = HtmlElement.fromTokens(startToken1, endToken1, parent, null);
const close = HtmlElement.fromTokens(startToken2, endToken2, parent, null);
expect(open.parent).toBeDefined();
expect(close.parent).toBeUndefined();
expect(close.parent).toBeNull();
});
it("should set metadata", () => {
......@@ -316,7 +316,7 @@ describe("HtmlElement", () => {
it("should return null for boolean attributes", () => {
expect.assertions(1);
const node = new HtmlElement("foo");
node.setAttribute("bar", undefined, location, null);
node.setAttribute("bar", null, location, null);
expect(node.getAttributeValue("bar")).toBeNull();
});
});
......@@ -489,7 +489,7 @@ describe("HtmlElement", () => {
} as MetaElement;
beforeEach(() => {
node = new HtmlElement("my-element", null, null, original);
node = new HtmlElement("my-element", null, NodeClosed.EndTag, original);
});
it("should overwrite copyable properties", () => {
......
......@@ -19,28 +19,28 @@ export enum NodeClosed {
export class HtmlElement extends DOMNode {
public readonly tagName: string;
public readonly parent: HtmlElement;
public readonly parent: HtmlElement | null;
public readonly voidElement: boolean;
public readonly depth: number;
public closed: NodeClosed;
protected readonly attr: { [key: string]: Attribute[] };
private metaElement: MetaElement;
private metaElement: MetaElement | null;
private annotation: string | null;
public constructor(
tagName: string,
parent?: HtmlElement,
parent: HtmlElement | null = null,
closed: NodeClosed = NodeClosed.EndTag,
meta?: MetaElement,
location?: Location
meta: MetaElement | null = null,
location: Location | null = null
) {
const nodeType = tagName ? NodeType.ELEMENT_NODE : NodeType.DOCUMENT_NODE;
super(nodeType, tagName, location);
this.tagName = tagName;
this.parent = parent;
this.parent = parent ?? null;
this.attr = {};
this.metaElement = meta;
this.metaElement = meta ?? null;
this.closed = closed;
this.voidElement = meta ? Boolean(meta.void) : false;
this.depth = 0;
......@@ -58,15 +58,15 @@ export class HtmlElement extends DOMNode {
}
}
public static rootNode(location: Location): HtmlElement {
return new HtmlElement(undefined, undefined, undefined, undefined, location);
public static rootNode(location: Location | null): HtmlElement {
return new HtmlElement(undefined, null, null, null, location);
}
public static fromTokens(
startToken: Token,
endToken: Token,
parent: HtmlElement,
metaTable: MetaTable
parent: HtmlElement | null = null,
metaTable: MetaTable | null = null
): HtmlElement {
const tagName = startToken.data[2];
if (!tagName) {
......@@ -80,7 +80,7 @@ export class HtmlElement extends DOMNode {
/* location contains position of '<' so strip it out */
const location = sliceLocation(startToken.location, 1);
return new HtmlElement(tagName, open ? parent : undefined, closed, meta, location);
return new HtmlElement(tagName, open ? parent : null, closed, meta, location);
}
/**
......
......@@ -6,7 +6,7 @@ import { Selector } from "./selector";
import { NodeType } from "./nodetype";
interface StrippedHtmlElement {
id: string;
id: string | null;
class: string | null;
nodeName: string;
nodeType: NodeType;
......
......@@ -56,14 +56,14 @@ describe("toBeValid()", () => {
it("should fail if report is invalid", async () => {
expect.assertions(3);
let error: Error;
let error: Error | undefined = undefined;
try {
await expect(reportError).toBeValid();
} catch (e) {
error = e;
}
expect(error).toBeDefined();
expect(error.message).toMatchSnapshot();
expect(error?.message).toMatchSnapshot();
});
});
......@@ -75,14 +75,14 @@ describe("toBeInvalid()", () => {
it("should fail if report is valid", async () => {
expect.assertions(3);
let error: Error;
let error: Error | undefined = undefined;
try {
await expect(reportOk).toBeInvalid();
} catch (e) {
error = e;
}
expect(error).toBeDefined();
expect(error.message).toMatchSnapshot();
expect(error?.message).toMatchSnapshot();
});
});
......@@ -101,19 +101,19 @@ describe("toHaveError()", () => {
it("should fail if error is missing", async () => {
expect.assertions(3);
let error: Error;
let error: Error | undefined = undefined;
try {
await expect(reportError).toHaveError("asdf", "asdf");
} catch (e) {
error = e;
}
expect(error).toBeDefined();
expect(stripAnsi(error.message)).toMatchSnapshot();
expect(stripAnsi(error?.message || "")).toMatchSnapshot();
});
it("should fail if error has mismatched context", async () => {
expect.assertions(3);
let error: Error;
let error: Error | undefined = undefined;
try {
await expect(reportError).toHaveError("my-rule", "mock message", {
foo: "spam",
......@@ -122,7 +122,7 @@ describe("toHaveError()", () => {
error = e;
}
expect(error).toBeDefined();
expect(stripAnsi(error.message)).toMatchSnapshot();
expect(stripAnsi(error?.message || "")).toMatchSnapshot();
});
});
......@@ -149,7 +149,7 @@ describe("toHaveErrors()", () => {
it("should fail if error any missing", async () => {
expect.assertions(3);
let error: Error;
let error: Error | undefined = undefined;
try {
await expect(reportMultipleErrors).toHaveErrors([
["my-rule", "mock message"],
......@@ -159,7 +159,7 @@ describe("toHaveErrors()", () => {
error = e;
}
expect(error).toBeDefined();
expect(stripAnsi(error.message)).toMatchSnapshot();
expect(stripAnsi(error?.message || "")).toMatchSnapshot();
});
});
......@@ -185,7 +185,7 @@ describe("toBeToken()", () => {
it("should fail if token doesn't match", async () => {
expect.assertions(3);
let error: Error;
let error: Error | undefined = undefined;
try {
await expect({ value: token }).toBeToken({
type: TokenType.TAG_CLOSE,
......@@ -194,7 +194,7 @@ describe("toBeToken()", () => {
error = e;
}
expect(error).toBeDefined();
expect(stripAnsi(error.message)).toMatchSnapshot();
expect(stripAnsi(error?.message || "")).toMatchSnapshot();
});
});
......@@ -211,14 +211,14 @@ describe("toHTMLValidate()", () => {
it("should fail if markup is invalid", async () => {
expect.assertions(3);
let error: Error;
let error: Error | undefined = undefined;
try {
await expect("<a><button></i>").toHTMLValidate();
} catch (e) {
error = e;
}
expect(error).toBeDefined();
expect(stripAnsi(error.message)).toMatchInlineSnapshot(`
expect(stripAnsi(error?.message || "")).toMatchInlineSnapshot(`
"Expected HTML to be valid but had the following errors:
Anchor link must have a text describing its purpose [wcag/h30]
......@@ -231,14 +231,14 @@ describe("toHTMLValidate()", () => {
it("should fail if markup is valid but negated", async () => {
expect.assertions(3);
let error: Error;
let error: Error | undefined = undefined;
try {
await expect("<p></p>").not.toHTMLValidate();
} catch (e) {
error = e;
}
expect(error).toBeDefined();
expect(stripAnsi(error.message)).toMatchInlineSnapshot(
expect(stripAnsi(error?.message || "")).toMatchInlineSnapshot(
`"HTML is valid when an error was expected"`
);
});
......@@ -329,7 +329,7 @@ describe("toHTMLValidate()", () => {
it("should fail if markup has wrong error", async () => {
expect.assertions(3);
let error: Error;
let error: Error | undefined = undefined;
try {
await expect("<u></i>").not.toHTMLValidate({
ruleId: "wrong-error",
......@@ -339,7 +339,7 @@ describe("toHTMLValidate()", () => {
error = e;
}
expect(error).toBeDefined();
expect(stripAnsi(error.message)).toMatchInlineSnapshot(`
expect(stripAnsi(error?.message || "")).toMatchInlineSnapshot(`
"expect(received).not.toHTMLValidate(expected) // expected error
Expected error to be present:
......
......@@ -172,7 +172,7 @@ describe("MetaTable", () => {
expect.assertions(2);
const meta = table.getMetaFor("foo");
expect(meta).not.toBeUndefined();
expect(meta.tagName).toEqual("foo");
expect(meta?.tagName).toEqual("foo");
});
it("should be null for unknown elements", () => {
......@@ -185,7 +185,7 @@ describe("MetaTable", () => {
expect.assertions(2);
const meta = table.getMetaFor("FOO");
expect(meta).not.toBeUndefined();
expect(meta.tagName).toEqual("foo");
expect(meta?.tagName).toEqual("foo");
});
});
......@@ -408,7 +408,7 @@ describe("MetaTable", () => {
});
const meta = table.getMetaFor("foo");
expect(meta).not.toBeUndefined();
expect(meta.attributes).toEqual({
expect(meta?.attributes).toEqual({
attr: [/foo/],
});
});
......@@ -425,7 +425,7 @@ describe("MetaTable", () => {
});
const meta = table.getMetaFor("foo");
expect(meta).not.toBeUndefined();
expect(meta.attributes).toEqual({
expect(meta?.attributes).toEqual({
attr: [/foo/i],
});
});
......@@ -442,7 +442,7 @@ describe("MetaTable", () => {
});
const meta = table.getMetaFor("foo");
expect(meta).not.toBeUndefined();
expect(meta.attributes).toEqual({
expect(meta?.attributes).toEqual({
attr: [/foo/],
});
});
......
......@@ -1078,7 +1078,8 @@ describe("parser", () => {
expect.assertions(2);
function processElement(this: ProcessElementContext, node: HtmlElement): void {
if (node.tagName === "i") {
node.loadMeta(this.getMetaFor("div"));
const meta = this.getMetaFor("div");
node.loadMeta(meta!);
}
}
const source: Source = {
......
......@@ -273,7 +273,7 @@ describe("Plugin", () => {
const a = metaTable.getMetaFor("my-element");
const b = metaTable.getMetaFor("my-element:real");
const node = new HtmlElement("my-element", null, null, a);
node.loadMeta(b);
node.loadMeta(b!);
expect(node.meta).toEqual({
tagName: "my-element",
foo: "copied" /* foo is marked for copying */,
......