eslint-plugin-import-x
Version:
Import with sanity.
110 lines • 4.25 kB
JavaScript
import path from 'node:path';
import debug from 'debug';
import { moduleRequire } from './module-require.js';
function withoutProjectParserOptions(opts) {
const { EXPERIMENTAL_useProjectService, project, projectService, ...rest } = opts;
return rest;
}
const log = debug('eslint-plugin-import-x:parse');
function keysFromParser(_parserPath, parserInstance, parsedResult) {
if (parsedResult && parsedResult.visitorKeys) {
return parsedResult.visitorKeys;
}
if (parserInstance &&
'VisitorKeys' in parserInstance &&
parserInstance.VisitorKeys) {
return parserInstance.VisitorKeys;
}
return null;
}
function makeParseReturn(ast, visitorKeys) {
return {
ast,
visitorKeys,
};
}
function stripUnicodeBOM(text) {
return text.codePointAt(0) === 0xfe_ff ? text.slice(1) : text;
}
function transformHashbang(text) {
return text.replace(/^#!([^\r\n]+)/u, (_, captured) => `//${captured}`);
}
export function parse(path, content, context) {
if (context == null) {
throw new Error('need context to parse properly');
}
let parserOptions = context.languageOptions?.parserOptions || context.parserOptions;
const parserOrPath = getParser(path, context);
if (!parserOrPath) {
throw new Error('parserPath or languageOptions.parser is required!');
}
parserOptions = { ...parserOptions };
parserOptions.ecmaFeatures = { ...parserOptions.ecmaFeatures };
parserOptions.comment = true;
parserOptions.attachComment = true;
parserOptions.tokens = true;
parserOptions.loc = true;
parserOptions.range = true;
parserOptions.filePath = path;
parserOptions = withoutProjectParserOptions(parserOptions);
parserOptions.ecmaVersion ??= context.languageOptions?.ecmaVersion;
parserOptions.sourceType ??= context.languageOptions?.sourceType;
const parser = typeof parserOrPath === 'string'
? moduleRequire(parserOrPath)
: parserOrPath;
content = transformHashbang(stripUnicodeBOM(String(content)));
if ('parseForESLint' in parser &&
typeof parser.parseForESLint === 'function') {
let ast;
try {
const parserRaw = parser.parseForESLint(content, parserOptions);
ast = parserRaw.ast;
return makeParseReturn(ast, keysFromParser(parserOrPath, parser, parserRaw));
}
catch (error_) {
const error = error_;
console.warn(`Error while parsing ${parserOptions.filePath}`);
console.warn(`Line ${error.lineNumber}, column ${error.column}: ${error.message}`);
}
if (!ast || typeof ast !== 'object') {
console.warn(`\`parseForESLint\` from parser \`${typeof parserOrPath === 'string' ? parserOrPath : 'context.languageOptions.parser'}\` is invalid and will just be ignored`, { content, parserMeta: parser.meta });
}
else {
return makeParseReturn(ast, keysFromParser(parserOrPath, parser));
}
}
if ('parse' in parser) {
const ast = parser.parse(content, parserOptions);
return makeParseReturn(ast, keysFromParser(parserOrPath, parser));
}
throw new Error('Parser must expose a `parse` or `parseForESLint` method');
}
function getParser(path, context) {
const parserPath = getParserPath(path, context);
if (parserPath) {
return parserPath;
}
const parser = 'languageOptions' in context && context.languageOptions?.parser;
if (parser &&
typeof parser !== 'string' &&
(('parse' in parser && typeof parse === 'function') ||
('parseForESLint' in parser &&
typeof parser.parseForESLint === 'function'))) {
return parser;
}
return null;
}
function getParserPath(filepath, context) {
const parsers = context.settings['import-x/parsers'];
if (parsers != null) {
const extension = path.extname(filepath);
for (const parserPath in parsers) {
if (parsers[parserPath].includes(extension)) {
log('using alt parser:', parserPath);
return parserPath;
}
}
}
return context.parserPath;
}
//# sourceMappingURL=parse.js.map