I'm trying to add HTMLHint into Codemirror 6 by following the lint documentation and the eslint-linter-browserify demo for Codemirror 6. Not sure what I'm doing wrong but the lints are not showing.
Can someone explain what I'm doing wrong and how can I add HTMLHint into Codemirror 6?
lang-html:
function HTMLHint(htmlhint, config) {
config = {
rules: {
"tagname-lowercase": true,
"attr-lowercase": true,
"attr-value-double-quotes": true,
"doctype-first": true,
"tag-pair": true,
"spec-char-escape": true,
"id-unique": true,
"src-not-empty": true,
"attr-no-duplication": true
}
}
return (view) => {
let { state } = view, found = [];
for (let { from, to } of htmlLanguage.findRegions(state)) {
let fromLine = state.doc.lineAt(from), offset = { line: fromLine.number - 1, col: from - fromLine.from, pos: from };
for (let d of htmlhint.verify(state.sliceDoc(from, to)))
found.push(translateDiagnostic(d, state.doc, offset));
}
return found;
};
}
function mapPos(line, col, doc, offset) {
return doc.line(line + offset.line).from + col + (line == 1 ? offset.col - 1 : -1);
}
function translateDiagnostic(input, doc, offset) {
let start = mapPos(input.line, input.column, doc, offset);
let result = {
from: start,
to: input.endLine != null && input.endColumn != 1 ? mapPos(input.endLine, input.endColumn, doc, offset) : start,
message: input.message,
source: input.ruleId ? "htmlhint:" + input.ruleId : "htmlhint",
severity: input.severity == 1 ? "warning" : "error",
};
if (input.fix) {
let { range, text } = input.fix, from = range[0] + offset.pos - start, to = range[1] + offset.pos - start;
result.actions = [{
name: "fix",
apply(view, start) {
view.dispatch({ changes: { from: start + from, to: start + to, insert: text }, scrollIntoView: true });
}
}];
}
return result;
}
export { autoCloseTags, HTMLHint, html, htmlCompletionSource, htmlCompletionSourceWith, htmlLanguage };
editor.js:
import { EditorView } from '@codemirror/view';
import { lineNumbers, highlightActiveLineGutter, highlightSpecialChars, drawSelection, dropCursor, rectangularSelection, crosshairCursor, highlightActiveLine, keymap } from '@codemirror/view';
import { EditorState } from '@codemirror/state';
import { foldGutter, indentOnInput, syntaxHighlighting, defaultHighlightStyle, bracketMatching, foldKeymap } from '@codemirror/language';
import { history, defaultKeymap, historyKeymap } from '@codemirror/commands';
import { highlightSelectionMatches, searchKeymap } from '@codemirror/search';
import { closeBrackets, autocompletion, closeBracketsKeymap, completionKeymap } from '@codemirror/autocomplete';
import { linter, lintKeymap, lintGutter } from '@codemirror/lint';
import { javascript } from "@codemirror/lang-javascript";
import { html, HTMLHint } from "@codemirror/lang-html";
import { htmlhint } from 'htmlhint';
// ruleSets for HTMLLint
let ruleSets = {
"tagname-lowercase": true,
"attr-lowercase": true,
"attr-value-double-quotes": true,
"doctype-first": false,
"tag-pair": true,
"spec-char-escape": true,
"id-unique": true,
"src-not-empty": true,
"attr-no-duplication": true
};
const basicSetup = [
lineNumbers(),
highlightActiveLineGutter(),
highlightSpecialChars(),
history(),
foldGutter(),
drawSelection(),
dropCursor(),
EditorState.allowMultipleSelections.of(true),
indentOnInput(),
syntaxHighlighting(defaultHighlightStyle),
bracketMatching(),
closeBrackets(),
autocompletion(),
rectangularSelection(),
crosshairCursor(),
highlightActiveLine(),
highlightSelectionMatches(),
lintGutter(),
linter(HTMLHint(ruleSets)),
keymap.of([
...closeBracketsKeymap,
...defaultKeymap,
...searchKeymap,
...historyKeymap,
...foldKeymap,
...completionKeymap,
...lintKeymap,
]),
html(),
];
const editor = new EditorView({
state: EditorState.create({
doc: `<span id="hi">hello world</span>
<span id="hi">hello world</span>`,
extensions: [basicSetup],
}),
parent: document.getElementById('editor'),
});
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<title>CodeMirror 6 Test</title>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<main>
<div id="editor"></div>
</main>
<script src="editor.bundle.js"></script>
</body>
</html>
I was able to accomplish this with Codemirror v5- with....
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
// Depends on htmlhint.js from http://htmlhint.com/js/htmlhint.js
// declare global: HTMLHint
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("htmlhint"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "htmlhint"], mod);
else // Plain browser env
mod(CodeMirror, window.HTMLHint);
})(function(CodeMirror, HTMLHint) {
"use strict";
var defaultRules = {
"tagname-lowercase": true,
"attr-lowercase": true,
"attr-value-double-quotes": true,
"doctype-first": false,
"tag-pair": true,
"spec-char-escape": true,
"id-unique": true,
"src-not-empty": true,
"attr-no-duplication": true
};
CodeMirror.registerHelper("lint", "html", function(text, options) {
var found = [];
if (HTMLHint && !HTMLHint.verify) {
if(typeof HTMLHint.default !== 'undefined') {
HTMLHint = HTMLHint.default;
} else {
HTMLHint = HTMLHint.HTMLHint;
}
}
if (!HTMLHint) HTMLHint = window.HTMLHint;
if (!HTMLHint) {
if (window.console) {
window.console.error("Error: HTMLHint not found, not defined on window, or not available through define/require, CodeMirror HTML linting cannot run.");
}
return found;
}
var messages = HTMLHint.verify(text, options && options.rules || defaultRules);
for (var i = 0; i < messages.length; i++) {
var message = messages[i];
var startLine = message.line - 1, endLine = message.line - 1, startCol = message.col - 1, endCol = message.col;
found.push({
from: CodeMirror.Pos(startLine, startCol),
to: CodeMirror.Pos(endLine, endCol),
message: message.message,
severity : message.type
});
}
return found;
});
});
You're using the
javascriptLanguage.findRegions
method in your HTMLHint function to find the parts of the page to lint, however this is wrong. Because you're working with HTML rather than JavaScript, you should use thehtmlLanguage.findRegions
function instead. Additionally, before you can utilise thehtmlhint
module in thelinter
extension, you must import it in youreditor.js
file.