markuplint
Advanced tools
Comparing version 0.7.0 to 0.8.0-alpha
@@ -13,3 +13,5 @@ "use strict"; | ||
const config = rule.optimizeOption(ruleset.rules[rule.name]); | ||
reports.push(...await rule.verify(nodeTree, config, ruleset, locale)); | ||
const verifyReturns = await rule.verify(nodeTree, config, ruleset, locale); | ||
const results = verifyReturns.map((v) => Object.assign(v, { ruleId: rule.name })); | ||
reports.push(...results); | ||
} | ||
@@ -16,0 +18,0 @@ } |
@@ -58,3 +58,4 @@ export interface NodeLocation { | ||
} | ||
export declare type Walker = (node: Node) => void; | ||
export declare type Walker = (node: Node) => Promise<void>; | ||
export declare type SyncWalker = (node: Node) => void; | ||
export declare abstract class Node { | ||
@@ -115,5 +116,6 @@ nodeName: string; | ||
readonly raw: string; | ||
walk(walker: Walker): void; | ||
walk(walker: Walker): Promise<void>; | ||
syncWalk(walker: SyncWalker): void; | ||
getNode(index: number): Node | null; | ||
} | ||
export default function parser(html: string): Document; |
@@ -98,3 +98,3 @@ "use strict"; | ||
const pos = []; | ||
walk(nodes, (node) => { | ||
syncWalk(nodes, (node) => { | ||
const i = pos.length; | ||
@@ -235,4 +235,9 @@ if (node instanceof InvalidNode) { | ||
} | ||
walk(walker) { | ||
async walk(walker) { | ||
for (const node of this._list) { | ||
await walker(node); | ||
} | ||
} | ||
syncWalk(walker) { | ||
for (const node of this._list) { | ||
walker(node); | ||
@@ -246,7 +251,15 @@ } | ||
exports.Document = Document; | ||
function walk(nodeList, walker) { | ||
async function walk(nodeList, walker) { | ||
for (const node of nodeList) { | ||
await walker(node); | ||
if (node instanceof Element || node instanceof InvalidNode) { | ||
await walk(node.childNodes, walker); | ||
} | ||
} | ||
} | ||
function syncWalk(nodeList, walker) { | ||
for (const node of nodeList) { | ||
walker(node); | ||
if (node instanceof Element || node instanceof InvalidNode) { | ||
walk(node.childNodes, walker); | ||
syncWalk(node.childNodes, walker); | ||
} | ||
@@ -253,0 +266,0 @@ } |
import { Document } from './parser'; | ||
import { Ruleset } from './ruleset'; | ||
export interface VerifiedResult { | ||
export interface VerifyReturn { | ||
level: RuleLevel; | ||
@@ -10,2 +10,5 @@ message: string; | ||
} | ||
export interface VerifiedResult extends VerifyReturn { | ||
ruleId: string; | ||
} | ||
export declare type RuleLevel = 'error' | 'warning'; | ||
@@ -23,5 +26,6 @@ export declare type RuleOption<T, O> = [RuleLevel, T, O]; | ||
readonly defaultValue: T; | ||
abstract verify(document: Document, config: RuleConfig<T, O>, ruleset: Ruleset, locale: string): Promise<VerifiedResult[]>; | ||
abstract verify(document: Document, config: RuleConfig<T, O>, ruleset: Ruleset, locale: string): Promise<VerifyReturn[]>; | ||
optimizeOption(option: RuleOption<T, O> | boolean): RuleConfig<T, O>; | ||
} | ||
export declare function getRuleModules(): Promise<Rule[]>; | ||
export declare function resolveRuleModules(pattern: RegExp, ruleDir: string): Promise<Rule[]>; |
@@ -6,2 +6,4 @@ "use strict"; | ||
const util = require("util"); | ||
// @ts-ignore | ||
const findNodeModules = require("find-node-modules"); | ||
const readdir = util.promisify(fs.readdir); | ||
@@ -32,18 +34,28 @@ class Rule { | ||
const rules = []; | ||
const ruleDir = path.resolve(__dirname, './rules'); | ||
const ruleFiles = await readdir(ruleDir); | ||
for (const filePath of ruleFiles) { | ||
if (/^markuplint-rule-[a-z]+(?:-[a-z]+)*(?:\.js)?$/i.test(filePath)) { | ||
try { | ||
const mod = await Promise.resolve().then(() => require(path.resolve(ruleDir, filePath))); | ||
const CustomRule /* Subclass of Rule */ = mod.default; | ||
rules.push(new CustomRule()); | ||
} | ||
catch (err) { | ||
// @ts-ignore | ||
if (err instanceof Error && err.code === 'MODULE_NOT_FOUND') { | ||
console.warn(`[markuplint] Cannot find rule module: ${filePath}`); | ||
rules.push(...await resolveRuleModules(/^markuplint-rule-[a-z]+(?:-[a-z]+)*(?:\.js)?$/i, path.resolve(__dirname, './rules'))); | ||
rules.push(...await resolveRuleModules(/^markuplint-rule-[a-z]+(?:-[a-z]+)*(?:\.js)?$/i, path.resolve(process.cwd(), './rules'))); | ||
rules.push(...await resolveRuleModules(/^markuplint-plugin-[a-z]+(?:-[a-z]+)*(?:\.js)?$/i, nearNodeModules())); | ||
return rules; | ||
} | ||
exports.getRuleModules = getRuleModules; | ||
async function resolveRuleModules(pattern, ruleDir) { | ||
const rules = []; | ||
try { | ||
const ruleFiles = await readdir(ruleDir); | ||
for (const filePath of ruleFiles) { | ||
if (pattern.test(filePath)) { | ||
try { | ||
const mod = await Promise.resolve().then(() => require(path.resolve(ruleDir, filePath))); | ||
let CustomRule /* Subclass of Rule */ = mod.default; | ||
CustomRule = CustomRule.rule || CustomRule; | ||
rules.push(new CustomRule()); | ||
} | ||
else { | ||
throw err; | ||
catch (err) { | ||
// @ts-ignore | ||
if (err instanceof Error && err.code === 'MODULE_NOT_FOUND') { | ||
console.warn(`[markuplint] Cannot find rule module: ${filePath} (${err.message})`); | ||
} | ||
else { | ||
throw err; | ||
} | ||
} | ||
@@ -53,4 +65,18 @@ } | ||
} | ||
catch (e) { | ||
// @ts-ignore | ||
if (!(e instanceof Error && e.code === 'ENOENT')) { | ||
throw e; | ||
} | ||
} | ||
return rules; | ||
} | ||
exports.getRuleModules = getRuleModules; | ||
exports.resolveRuleModules = resolveRuleModules; | ||
function nearNodeModules() { | ||
const moduleDirs = findNodeModules({ cwd: process.cwd() }).map((dir) => path.resolve(dir)); | ||
const moduleDir = moduleDirs[0]; | ||
if (!moduleDir) { | ||
throw new Error(`Directory node_module not found.`); | ||
} | ||
return moduleDir; | ||
} |
import { Document } from '../../parser'; | ||
import Rule, { RuleConfig, VerifiedResult } from '../../rule'; | ||
import Rule, { RuleConfig, VerifyReturn } from '../../rule'; | ||
import { Ruleset } from '../../ruleset'; | ||
export default class extends Rule { | ||
name: string; | ||
verify(document: Document, config: RuleConfig, ruleset: Ruleset, locale: string): Promise<VerifiedResult[]>; | ||
verify(document: Document, config: RuleConfig, ruleset: Ruleset, locale: string): Promise<VerifyReturn[]>; | ||
} |
@@ -14,3 +14,3 @@ "use strict"; | ||
const message = await messages_1.default(locale, 'Duplicate {0}', 'attribute name'); | ||
document.walk((node) => { | ||
await document.walk(async (node) => { | ||
if (node instanceof parser_1.Element) { | ||
@@ -17,0 +17,0 @@ const attrNameStack = []; |
import { Document } from '../../parser'; | ||
import Rule, { RuleConfig, RuleLevel, VerifiedResult } from '../../rule'; | ||
import Rule, { RuleConfig, RuleLevel, VerifyReturn } from '../../rule'; | ||
import { Ruleset } from '../../ruleset'; | ||
@@ -9,3 +9,3 @@ export declare type Value = 'double' | 'single'; | ||
defaultValue: Value; | ||
verify(document: Document, config: RuleConfig<Value>, ruleset: Ruleset, locale: string): Promise<VerifiedResult[]>; | ||
verify(document: Document, config: RuleConfig<Value>, ruleset: Ruleset, locale: string): Promise<VerifyReturn[]>; | ||
} |
@@ -20,3 +20,3 @@ "use strict"; | ||
const message = await messages_1.default(locale, '{0} is must {1} on {2}', 'Attribute value', 'quote', `${config.value} quotation mark`); | ||
document.walk((node) => { | ||
await document.walk(async (node) => { | ||
if (node instanceof parser_1.Element) { | ||
@@ -23,0 +23,0 @@ for (const attr of node.attributes) { |
import { Document } from '../../parser'; | ||
import Rule, { RuleConfig, RuleLevel, VerifiedResult } from '../../rule'; | ||
import Rule, { RuleConfig, RuleLevel, VerifyReturn } from '../../rule'; | ||
import { Ruleset } from '../../ruleset'; | ||
@@ -9,3 +9,3 @@ export declare type Value = 'lower' | 'upper'; | ||
defaultValue: Value; | ||
verify(document: Document, config: RuleConfig<Value>, ruleset: Ruleset, locale: string): Promise<VerifiedResult[]>; | ||
verify(document: Document, config: RuleConfig<Value>, ruleset: Ruleset, locale: string): Promise<VerifyReturn[]>; | ||
} |
@@ -18,3 +18,3 @@ "use strict"; | ||
const message = await messages_1.default(locale, `{0} of {1} ${ms} be {2}`, 'Attribute name', 'HTML', `${config.value}case`); | ||
document.walk((node) => { | ||
await document.walk(async (node) => { | ||
if (node instanceof parser_1.Element && node.namespaceURI === 'http://www.w3.org/1999/xhtml') { | ||
@@ -21,0 +21,0 @@ if (node.attributes) { |
import { Document } from '../../parser'; | ||
import Rule, { RuleConfig, RuleLevel, VerifiedResult } from '../../rule'; | ||
import Rule, { RuleConfig, RuleLevel, VerifyReturn } from '../../rule'; | ||
import { Ruleset } from '../../ruleset'; | ||
@@ -9,3 +9,3 @@ export declare type Value = 'lower' | 'upper'; | ||
defaultValue: Value; | ||
verify(document: Document, config: RuleConfig<Value>, ruleset: Ruleset, locale: string): Promise<VerifiedResult[]>; | ||
verify(document: Document, config: RuleConfig<Value>, ruleset: Ruleset, locale: string): Promise<VerifyReturn[]>; | ||
} |
@@ -18,3 +18,3 @@ "use strict"; | ||
const message = await messages_1.default(locale, `{0} of {1} ${ms} be {2}`, 'Tag name', 'HTML', `${config.value}case`); | ||
document.walk((node) => { | ||
await document.walk(async (node) => { | ||
if ((node instanceof parser_1.Element && node.namespaceURI === 'http://www.w3.org/1999/xhtml') | ||
@@ -21,0 +21,0 @@ || |
import { Document } from '../../parser'; | ||
import Rule, { RuleConfig, VerifiedResult } from '../../rule'; | ||
import Rule, { RuleConfig, VerifyReturn } from '../../rule'; | ||
import { Ruleset } from '../../ruleset'; | ||
@@ -9,3 +9,3 @@ export declare type Value = boolean; | ||
name: string; | ||
verify(document: Document, config: RuleConfig<Value, Options>, ruleset: Ruleset, locale: string): Promise<VerifiedResult[]>; | ||
verify(document: Document, config: RuleConfig<Value, Options>, ruleset: Ruleset, locale: string): Promise<VerifyReturn[]>; | ||
} |
@@ -22,3 +22,3 @@ "use strict"; | ||
const message = await messages_1.default(locale, `{0} ${ms} {1}`, 'Illegal characters', 'escape in character reference'); | ||
document.walk((node) => { | ||
await document.walk(async (node) => { | ||
const targetNodes = []; | ||
@@ -25,0 +25,0 @@ if (node instanceof parser_1.TextNode) { |
import { Document } from '../../parser'; | ||
import Rule, { RuleConfig, VerifiedResult } from '../../rule'; | ||
import Rule, { RuleConfig, VerifyReturn } from '../../rule'; | ||
import { Ruleset } from '../../ruleset'; | ||
export default class extends Rule { | ||
name: string; | ||
verify(document: Document, config: RuleConfig, ruleset: Ruleset, locale: string): Promise<VerifiedResult[]>; | ||
verify(document: Document, config: RuleConfig, ruleset: Ruleset, locale: string): Promise<VerifyReturn[]>; | ||
} |
@@ -15,3 +15,3 @@ "use strict"; | ||
const idStack = []; | ||
document.walk((node) => { | ||
await document.walk(async (node) => { | ||
if (node instanceof parser_1.Element) { | ||
@@ -18,0 +18,0 @@ const id = node.id; |
import { Document } from '../../parser'; | ||
import Rule, { RuleConfig, VerifiedResult } from '../../rule'; | ||
import Rule, { RuleConfig, VerifyReturn } from '../../rule'; | ||
import { Ruleset } from '../../ruleset'; | ||
@@ -12,3 +12,3 @@ export declare type DefaultValue = 'tab' | number; | ||
name: string; | ||
verify(document: Document, config: RuleConfig<DefaultValue>, ruleset: Ruleset): Promise<VerifiedResult[]>; | ||
verify(document: Document, config: RuleConfig<DefaultValue>, ruleset: Ruleset): Promise<VerifyReturn[]>; | ||
} |
@@ -18,3 +18,3 @@ "use strict"; | ||
let lastNode; | ||
document.walk((node) => { | ||
await document.walk(async (node) => { | ||
if (lastNode instanceof parser_1.TextNode) { | ||
@@ -21,0 +21,0 @@ const matched = lastNode.textContent.match(/\n(\s+$)/); |
import { Document } from '../../parser'; | ||
import Rule, { RuleConfig, VerifiedResult } from '../../rule'; | ||
import Rule, { RuleConfig, VerifyReturn } from '../../rule'; | ||
import { Ruleset } from '../../ruleset'; | ||
@@ -11,3 +11,3 @@ /** | ||
name: string; | ||
verify(document: Document, config: RuleConfig, ruleset: Ruleset): Promise<VerifiedResult[]>; | ||
verify(document: Document, config: RuleConfig, ruleset: Ruleset): Promise<VerifyReturn[]>; | ||
} |
@@ -24,3 +24,3 @@ "use strict"; | ||
} | ||
document.walk((node) => { | ||
await document.walk(async (node) => { | ||
if (node instanceof parser_1.Element && node.nodeName === nodeRule.nodeType) { | ||
@@ -27,0 +27,0 @@ if (nodeRule.permittedContent) { |
@@ -57,4 +57,7 @@ { | ||
"required-class-elements": true, | ||
"custom-element-naming": true | ||
"custom-element-naming": true, | ||
// Plugin | ||
"textlint/textlint": true | ||
} | ||
} |
{ | ||
"name": "markuplint", | ||
"version": "0.7.0", | ||
"version": "0.8.0-alpha", | ||
"description": "HTML linter for legacy/modern HTML, Web Components, SVG, MathML, AMP HTML and more.", | ||
@@ -27,2 +27,3 @@ "main": "lib/index.js", | ||
"deep-assign": "^2.0.0", | ||
"find-node-modules": "^1.0.4", | ||
"meow": "^4.0.0", | ||
@@ -45,2 +46,3 @@ "node-fetch": "^1.7.3", | ||
"del": "^3.0.0", | ||
"eslint": "^4.13.1", | ||
"gulp": "^3.9.1", | ||
@@ -50,4 +52,7 @@ "gulp-ava": "^0.18.0", | ||
"jsdom": "^11.5.1", | ||
"markuplint-plugin-textlint": "^0.1.0", | ||
"nyc": "^11.3.0", | ||
"run-sequence": "^2.2.0", | ||
"textlint": "^9.1.1", | ||
"textlint-rule-preset-japanese": "^2.0.0", | ||
"tslint": "^5.8.0", | ||
@@ -54,0 +59,0 @@ "typescript": "^2.6.2" |
303764
7088
9
21
+ Addedfind-node-modules@^1.0.4
+ Addedarr-diff@2.0.0(transitive)
+ Addedarr-flatten@1.1.0(transitive)
+ Addedarray-unique@0.2.1(transitive)
+ Addedbraces@1.8.5(transitive)
+ Addeddetect-file@0.1.0(transitive)
+ Addedexpand-brackets@0.1.5(transitive)
+ Addedexpand-range@1.8.2(transitive)
+ Addedexpand-tilde@1.2.2(transitive)
+ Addedextglob@0.3.2(transitive)
+ Addedfilename-regex@2.0.1(transitive)
+ Addedfill-range@2.2.4(transitive)
+ Addedfind-node-modules@1.0.4(transitive)
+ Addedfindup-sync@0.4.2(transitive)
+ Addedfor-in@1.0.2(transitive)
+ Addedfor-own@0.1.5(transitive)
+ Addedfs-exists-sync@0.1.0(transitive)
+ Addedglob-base@0.3.0(transitive)
+ Addedglob-parent@2.0.0(transitive)
+ Addedglobal-modules@0.2.3(transitive)
+ Addedglobal-prefix@0.1.5(transitive)
+ Addedhomedir-polyfill@1.0.3(transitive)
+ Addedini@1.3.8(transitive)
+ Addedis-buffer@1.1.6(transitive)
+ Addedis-dotfile@1.0.3(transitive)
+ Addedis-equal-shallow@0.1.3(transitive)
+ Addedis-extendable@0.1.1(transitive)
+ Addedis-extglob@1.0.0(transitive)
+ Addedis-glob@2.0.1(transitive)
+ Addedis-number@2.1.04.0.0(transitive)
+ Addedis-posix-bracket@0.1.1(transitive)
+ Addedis-primitive@2.0.0(transitive)
+ Addedis-windows@0.2.0(transitive)
+ Addedisarray@1.0.0(transitive)
+ Addedisobject@2.1.0(transitive)
+ Addedkind-of@3.2.26.0.3(transitive)
+ Addedmath-random@1.0.4(transitive)
+ Addedmerge@1.2.1(transitive)
+ Addedmicromatch@2.3.11(transitive)
+ Addednormalize-path@2.1.1(transitive)
+ Addedobject.omit@2.0.1(transitive)
+ Addedos-homedir@1.0.2(transitive)
+ Addedparse-glob@3.0.4(transitive)
+ Addedparse-passwd@1.0.0(transitive)
+ Addedpreserve@0.2.0(transitive)
+ Addedrandomatic@3.1.1(transitive)
+ Addedregex-cache@0.4.4(transitive)
+ Addedremove-trailing-separator@1.1.0(transitive)
+ Addedrepeat-element@1.1.4(transitive)
+ Addedrepeat-string@1.6.1(transitive)
+ Addedresolve-dir@0.1.1(transitive)