Spec-Zone.ru › ESLint

Пользовательские парсеры

Пользовательские парсеры ESLint позволяют расширить ESLint для поддержки проверки новых нестандартных возможностей языка JavaScript или пользовательского синтаксиса в коде. Парсер отвечает за преобразование вашего кода в абстрактное синтаксическое дерево (AST), которое ESLint затем может анализировать и проверять.

Создание пользовательского парсера

Методы пользовательских парсеров

Пользовательский парсер — это объект JavaScript с методом parse() или parseForESLint(). Метод parse возвращает только AST, тогда как parseForESLint() также возвращает дополнительные значения, позволяющие парсеру ещё больше настраивать поведение ESLint.

Оба метода должны быть собственными свойствами экземпляра и принимать исходный код в качестве первого аргумента, а необязательный объект конфигурации — в качестве второго аргумента. В файле конфигурации он задаётся как parserOptions.

// customParser.js

const espree = require("espree");

// Logs the duration it takes to parse each file.
function parse(code, options) {
	const label = `Parsing file "${options.filePath}"`;
	console.time(label);
	const ast = espree.parse(code, options);
	console.timeEnd(label);
	return ast; // Only the AST is returned.
}

module.exports = { parse };

Объект, возвращаемый parse

Метод parse должен просто возвращать объект AST.

Объект, возвращаемый parseForESLint

Метод parseForESLint должен возвращать объект, содержащий обязательное свойство ast и необязательные свойства services, scopeManager и visitorKeys.

  • ast должно содержать объект AST.
  • services может содержать любые зависящие от парсера сервисы (например, средства проверки типов узлов). Значение свойства services доступно правилам как context.sourceCode.parserServices. По умолчанию это пустой объект.
  • scopeManager может быть объектом ScopeManager. Пользовательские парсеры могут применять настраиваемый анализ областей видимости для экспериментального или расширенного синтаксиса. По умолчанию используется объект ScopeManager, создаваемый eslint-scope.
    • Поддержка scopeManager добавлена в ESLint v4.14.0. Версии ESLint с поддержкой scopeManager предоставляют свойство eslintScopeManager: true в parserOptions, которое можно использовать для определения наличия этой возможности.
    • Начиная с ESLint v10.0.0, ScopeManager должен автоматически разрешать ссылки на глобальные переменные, объявленные в коде, и предоставлять метод экземпляра addGlobals(names: string[]), который создаёт переменные с заданными именами в глобальной области видимости и разрешает ссылки на них.
  • visitorKeys может быть объектом для настройки обхода AST. Ключи объекта — это типы узлов AST. Каждое значение представляет собой массив имён свойств, которые следует обходить. По умолчанию используются KEYS из eslint-visitor-keys.
    • Поддержка visitorKeys добавлена в ESLint v4.14.0. Версии ESLint с поддержкой visitorKeys предоставляют свойство eslintVisitorKeys: true в parserOptions, которое можно использовать для определения наличия этой возможности.

Метаданные пользовательских парсеров

Для упрощения отладки и повышения эффективности кэширования пользовательских парсеров рекомендуется указать имя и версию в объекте meta в корне пользовательского парсера, как показано ниже:

// preferred location of name and version
module.exports = {
	meta: {
		name: "eslint-parser-custom",
		version: "1.2.3",
	},
};

Свойство meta.name должно совпадать с именем npm-пакета пользовательского парсера, а свойство meta.version — с версией npm-пакета. Проще всего получить эти сведения из файла package.json.

Спецификация AST

AST, создаваемое пользовательскими парсерами, основано на ESTree. AST требуется несколько дополнительных свойств, содержащих подробную информацию об исходном коде.

Все узлы

У всех узлов должно быть свойство range.

  • range (number[]) — это массив из двух чисел. Оба числа представляют собой индекс, отсчитываемый от нуля, то есть позицию в массиве символов исходного кода. Первое число — позиция начала узла, второе — позиция его конца. code.slice(node.range[0], node.range[1]) должно содержать текст узла. Этот диапазон не включает пробелы и скобки, окружающие узел.
  • loc (SourceLocation) не должно быть null. Свойство loc в ESTree определено как допускающее значение null, но ESLint требует наличия этого свойства. Свойство SourceLocation#source может иметь значение undefined. ESLint не использует свойство SourceLocation#source.

Свойство parent у всех узлов должно допускать перезапись. Прежде чем правила получат доступ к AST, ESLint во время обхода задаёт свойству parent каждого узла значение его родительского узла.

Узел Program

Узел Program должен иметь свойства tokens и comments. Оба свойства представляют собой массивы, содержащие элементы, соответствующие приведённому ниже интерфейсу Token.

interface Token {
	type: string;
	loc: SourceLocation;
	// See the "All Nodes" section for details of the `range` property.
	range: [number, number];
	value: string;
}
  • tokens (Token[]) — это массив токенов, влияющих на поведение программ. Между токенами могут находиться произвольные пробелы, поэтому правила проверяют Token#range, чтобы обнаружить пробелы между токенами. Массив должен быть отсортирован по Token#range[0].
  • comments (Token[]) — это массив токенов комментариев. Массив должен быть отсортирован по Token#range[0].

Диапазоны индексов всех токенов и комментариев не должны пересекаться с диапазонами других токенов и комментариев.

Узел Literal

Узел Literal должен иметь свойство raw.

  • raw (string) — это исходный код этого литерала. Он совпадает с code.slice(node.range[0], node.range[1]).

Публикация пользовательского парсера

Чтобы опубликовать пользовательский парсер в npm, выполните следующие действия:

  1. Создайте пользовательский парсер, следуя приведённому выше разделу Создание пользовательского парсера.
  2. Создайте npm-пакет для пользовательского парсера.
  3. В файле package.json укажите в поле main файл, экспортирующий пользовательский парсер.
  4. Опубликуйте npm-пакет.

Дополнительные сведения о публикации npm-пакета см. в документации npm.

После публикации npm-пакета его можно использовать, добавив пакет в проект. Например:

npm

npm install --save-dev eslint-parser-myparser

yarn

yarn add --dev eslint-parser-myparser

pnpm

pnpm add --save-dev eslint-parser-myparser

bun

bun add --dev eslint-parser-myparser

Затем добавьте пользовательский парсер в файл конфигурации ESLint с помощью свойства languageOptions.parser. Например:

// eslint.config.js

const { defineConfig } = require("eslint/config");
const myparser = require("eslint-parser-myparser");

module.exports = defineConfig([
	{
		languageOptions: {
			parser: myparser,
		},
		// ... rest of configuration
	},
]);

При использовании устаревшего формата конфигурации укажите свойство parser в виде строки:

// .eslintrc.js

module.exports = {
	parser: "eslint-parser-myparser",
	// ... rest of configuration
};

Дополнительные сведения об использовании парсеров ESLint в проекте см. в разделе Настройка парсера.

Пример

Сложный пример пользовательского парсера см. в исходном коде @typescript-eslint/parser.

Простой пользовательский парсер, предоставляющий правилам метод context.sourceCode.parserServices.foo().

// awesome-custom-parser.js
var espree = require("espree");
function parseForESLint(code, options) {
	return {
		ast: espree.parse(code, options),
		services: {
			foo: function () {
				console.log("foo");
			},
		},
		scopeManager: null,
		visitorKeys: null,
	};
}

module.exports = { parseForESLint };

Добавьте пользовательский парсер в файл конфигурации ESLint:

// eslint.config.js
const { defineConfig } = require("eslint/config");

module.exports = defineConfig([
	{
		languageOptions: {
			parser: require("./path/to/awesome-custom-parser"),
		},
	},
]);

Или, если используется устаревший формат конфигурации:

// .eslintrc.json
{
    "parser": "./path/to/awesome-custom-parser.js"
}

© OpenJS Foundation and other contributors
Licensed under the MIT License.
https://eslint.org/docs/latest/extend/custom-parsers

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API