or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-eslint-plugin-html

A ESLint plugin to lint and fix inline scripts contained in HTML files.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/eslint-plugin-html@8.1.x

To install, run

npx @tessl/cli install tessl/npm-eslint-plugin-html@8.1.0

index.mddocs/

ESLint Plugin HTML

ESLint Plugin HTML enables linting and fixing of JavaScript code embedded within HTML script tags, providing developers with the ability to apply ESLint rules to inline JavaScript in HTML files. It intelligently parses HTML and XML documents, extracts JavaScript content from script tags, and applies ESLint analysis while maintaining proper scope handling across multiple script tags within the same file.

Package Information

  • Package Name: eslint-plugin-html
  • Package Type: npm
  • Language: JavaScript
  • Installation: npm install --save-dev eslint-plugin-html
  • Node.js Version: >=16.0.0

Core Imports

ESLint 9+ (flat config):

import html from "eslint-plugin-html";

ESLint 8 and below:

const html = require("eslint-plugin-html");

Note: This plugin automatically patches ESLint's internal verification methods when imported, so no explicit API calls are needed. The main export is an empty object ({}) - functionality is provided through the automatic patching mechanism.

Basic Usage

ESLint 9+ Configuration (Flat Config)

import html from "eslint-plugin-html";

export default [
  {
    files: ["**/*.html"],
    plugins: { html },
    settings: {
      "html/html-extensions": [".html", ".htm"],
      "html/indent": "+2"
    }
  }
];

ESLint 8 and Below Configuration

{
  "plugins": ["html"],
  "settings": {
    "html/html-extensions": [".html", ".htm"],
    "html/indent": "+2"
  }
}

HTML File Example

<!DOCTYPE html>
<html>
<head>
  <title>Example</title>
</head>
<body>
  <script>
    // This JavaScript will be linted by ESLint
    const greeting = "Hello, World!";
    console.log(greeting);
  </script>
  
  <!-- eslint-disable-next-script -->
  <script>
    // This script will be ignored by ESLint
    var templateCode = <%= someTemplateVariable %>;
  </script>
</body>
</html>

Architecture

ESLint Plugin HTML works by:

  1. ESLint Patching: Automatically patches ESLint's internal verification methods to intercept HTML file processing
  2. HTML Parsing: Uses htmlparser2 to parse HTML/XML content and identify script tags
  3. JavaScript Extraction: Extracts JavaScript code from script tags while preserving location information
  4. Scope Management: Handles variable scopes across multiple script tags (shared by default, isolated for ES modules)
  5. Message Remapping: Maps ESLint error messages back to original HTML file locations
  6. Auto-fixing: Supports ESLint's auto-fix functionality for embedded JavaScript

ESLint Integration

The plugin works by automatically discovering and patching ESLint's internal modules when imported. This happens through runtime modification of ESLint's verification functions.

// Core patching functions (internal)
function iterateESLintModules(fn: Function): void;
function patch(module: Object): void;
function getLinterFromModule(module: Object): Function | undefined;

ESLint Patching Process

// ESLint legacy mode patching (ESLint 6-8)
function createVerifyPatch(verify: Function): Function;

// ESLint flat config mode patching (ESLint 9+)  
function createVerifyWithFlatConfigPatch(
  eslintModule: Object, 
  verifyWithFlatConfig: Function
): Function;

The patching mechanism searches for ESLint modules in the require cache and modifies their verification methods to process HTML files before standard JavaScript linting.

Core Processing Functions

The plugin provides several core functions for HTML parsing, JavaScript extraction, and message handling.

HTML Parsing and Script Extraction

/**
 * Iterates through HTML content and identifies script chunks
 * @param code - HTML source code  
 * @param xmlMode - Whether to parse in XML mode
 * @param options - Plugin settings object
 * @param onChunk - Callback function for each HTML/script chunk
 */
function iterateScripts(
  code: string, 
  xmlMode: boolean, 
  options: PluginSettings, 
  onChunk: (chunk: Chunk) => void
): void;

interface Chunk {
  type: "html" | "script";
  start: number;
  end: number;
  cdata: Array<{ start: number; end: number }>;
}

External Plugin Integration

/**
 * Handles integration with external HTML plugins like @html-eslint/parser
 * @param config - ESLint configuration object
 * @param callOriginalVerify - Function to call original ESLint verify
 * @returns Array containing messages and modified config
 */
function verifyExternalHtmlPlugin(
  config: Object, 
  callOriginalVerify: Function
): [Object[], Object];

Capabilities

HTML Comment Controls

Control ESLint behavior using HTML comments to disable/enable linting for specific script tags.

<!-- eslint-disable -->
<!-- eslint-enable -->
<!-- eslint-disable-next-script -->

Usage Examples:

<!-- Disable ESLint for all following scripts until re-enabled -->
<!-- eslint-disable -->
<script>
  var foo = 1; // This won't be linted
</script>
<!-- eslint-enable -->

<!-- Disable ESLint for only the next script tag -->
<!-- eslint-disable-next-script -->  
<script>
  var template = <%= serverVariable %>; // Template syntax ignored
</script>
<script>
  const normalCode = "This will be linted"; // This will be linted normally
</script>

Configuration Settings

Configure the plugin behavior through ESLint settings under the html namespace.

Internal Constants

// HTML comment processing states (from src/extract.js)
const NO_IGNORE = 0;
const IGNORE_NEXT = 1; 
const IGNORE_UNTIL_ENABLE = 2;

// Internal rule names for plugin processing
const PREPARE_RULE_NAME = "__eslint-plugin-html-prepare";
const PREPARE_PLUGIN_NAME = "__eslint-plugin-html-prepare";

File Extension Settings

// Settings object properties
"html/html-extensions": string[]  // HTML file extensions (default: [".erb", ".handlebars", ".hbs", ".htm", ".html", ".mustache", ".nunjucks", ".php", ".tag", ".riot", ".twig", ".we"])
"html/xml-extensions": string[]   // XML file extensions (default: [".xhtml", ".xml"])

JavaScript Processing Settings

// Settings object properties  
"html/javascript-tag-names": string[]        // Tag names to treat as JavaScript containers (default: ["script"])
"html/javascript-mime-types": (string | RegExp)[]  // MIME types to identify JavaScript content
"html/ignore-tags-without-type": boolean     // Ignore script tags without type attribute (default: false)

Indentation Settings

// Settings object properties
"html/indent": string           // Indentation pattern (e.g., "4", "tab", "+2") 
"html/report-bad-indent": number | string  // Report indentation errors: 0/"off", 1/"warn", 2/"error"

Usage Examples:

// ESLint 9+ flat config
export default [
  {
    files: ["**/*.html", "**/*.php"],
    plugins: { html },
    settings: {
      "html/html-extensions": [".html", ".php", ".erb"],
      "html/javascript-tag-names": ["script", "customscript"],
      "html/javascript-mime-types": ["text/javascript", "/^text\\/(javascript|jsx)$/"],
      "html/indent": "+2",  // Relative to script tag indentation
      "html/report-bad-indent": "error",
      "html/ignore-tags-without-type": false
    }
  }
];

Multi-Script Scope Handling

Control how variables are shared between multiple script tags in the same HTML file.

// ESLint parser options
{
  languageOptions: {
    sourceType: "script" | "module"  // "script" shares scopes, "module" isolates them
  }
}

Script Scope Examples:

<!-- With sourceType: "script" (default) - scopes are shared -->
<script>
  var globalVar = "shared";
</script>
<script>
  console.log(globalVar); // ✓ Valid - variable is accessible
</script>

<!-- With sourceType: "module" - each script has isolated scope -->
<script>
  var moduleVar = "isolated";  // ⚠ no-unused-vars warning
</script>
<script>
  console.log(moduleVar);  // ❌ no-undef error
</script>

Internal Processing Functions

The plugin exposes internal processing functions for advanced use cases, though these are primarily used internally.

// From src/settings.js
function getSettings(settings: object): PluginSettings;

interface PluginSettings {
  htmlExtensions: string[];
  xmlExtensions: string[];
  javaScriptTagNames: string[];
  indent: { relative: boolean; spaces: string } | null;
  reportBadIndent: number;
  isJavaScriptMIMEType(type: string): boolean;
  ignoreTagsWithoutType: boolean;
}
// From src/extract.js  
function extract(code: string, xmlMode: boolean, options: PluginSettings): ExtractionResult;

interface ExtractionResult {
  code: TransformableString[];
  badIndentationLines: number[];
  hasBOM: boolean;
}
// From src/TransformableString.js
class TransformableString {
  constructor(original: string);
  toString(): string;
  replace(from: number, to: number, str: string): void;
  originalIndex(index: number): number | undefined;
  originalLocation(location: object): object | undefined;
  getOriginalLine(n: number): string;
}
// From src/getFileMode.js
function getFileMode(pluginSettings: PluginSettings, filenameOrOptions: string | object): "html" | "xml" | undefined;
// From src/remapMessages.js
const { remapMessages } = require("./remapMessages");
function remapMessages(messages: object[], hasBOM: boolean, codePart: TransformableString): object[];
// From src/utils.js
const { oneLine, splatSet } = require("./utils");

/**
 * Formats template literal strings to single line by joining and trimming
 * @param parts - Template literal parts array (also uses arguments object)
 * @returns Single line formatted string
 */
function oneLine(parts: TemplateStringsArray): string;

/**
 * Flattens nested arrays/sets into a single Set
 * @param items - Items to flatten (can be arrays, sets, or individual items)
 * @returns Flattened Set containing all items
 */
function splatSet(items: any): Set<any>;

// Additional utility functions from src/settings.js
/**
 * Filters items from array that exist in exclude array
 * @param array - Source array to filter
 * @param excludeArray - Array of items to exclude
 * @returns Filtered array without excluded items
 */
function filterOut(array: any[], excludeArray?: any[]): any[];

/**
 * Compiles a string representation of a regex into a RegExp object
 * @param re - String regex in format "/pattern/flags"
 * @returns Compiled RegExp object
 */
function compileRegExp(re: string): RegExp;

/**
 * Gets a setting value from nested or flat settings object
 * @param settings - ESLint settings object
 * @param name - Setting name to retrieve
 * @returns Setting value or undefined
 */
function getSetting(settings: object, name: string): any;
// From src/verifyWithSharedScopes.js
const { verifyWithSharedScopes } = require("./verifyWithSharedScopes");

/**
 * Processes multiple script tags with shared variable scopes
 * @param codeParts - Array of TransformableString instances
 * @param verifyCodePart - Function callback for verifying individual code parts
 * @param parserOptions - ESLint parser options
 */
function verifyWithSharedScopes(
  codeParts: TransformableString[], 
  verifyCodePart: Function, 
  parserOptions: object
): void;

Types

// ESLint configuration integration
interface ESLintFlatConfig {
  files: string[];
  plugins: { html: typeof import("eslint-plugin-html") };
  settings?: {
    "html/html-extensions"?: string[];
    "html/xml-extensions"?: string[];
    "html/javascript-tag-names"?: string[];
    "html/javascript-mime-types"?: (string | RegExp)[];
    "html/ignore-tags-without-type"?: boolean;
    "html/indent"?: string;
    "html/report-bad-indent"?: number | string;
  };
}

// Legacy ESLint configuration
interface ESLintLegacyConfig {
  plugins: string[];
  settings?: {
    [key: string]: any;
  };
}

Compatibility

ESLint Versions

  • ESLint 9+: Full support with flat configuration format
  • ESLint 8 and below: Full support with legacy configuration format
  • ESLint 6+: Supported with internal API adaptations
  • ESLint 5 and below: Limited support

Integration with Other HTML Linters

Works alongside:

  • @html-eslint/parser and @html-eslint/eslint-plugin
  • @angular-eslint/template-* rules

Template Engine Support

Supports linting JavaScript in templates:

  • PHP: Use with eslint-plugin-php-markup for enhanced PHP support
  • ERB, Handlebars, Twig: Supported via HTML comment controls
  • Vue.js: Not compatible - use eslint-plugin-vue instead

Error Handling

The plugin handles various error conditions:

  • Template Syntax: Use HTML comments to disable linting for template-heavy scripts
  • Invalid JavaScript: Reports parsing errors with original HTML line numbers
  • Indentation Issues: Configurable reporting of indentation problems
  • MIME Type Mismatches: Flexible MIME type detection with regex support
  • Missing ESLint: Warns when ESLint modules aren't found in require cache