vscode/.eslintplugin/code-no-runtime-import.ts

67 lines
2.1 KiB
TypeScript

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { TSESTree } from '@typescript-eslint/typescript-estree';
import * as eslint from 'eslint';
import { dirname, join, relative } from 'path';
import minimatch from 'minimatch';
import { createImportRuleListener } from './utils';
export = new class implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
layerbreaker: 'You are only allowed to import {{import}} from here using `import type ...`.'
},
schema: {
type: "array",
items: {
type: "object",
additionalProperties: {
type: "array",
items: {
type: "string"
}
}
}
}
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
let fileRelativePath = relative(dirname(__dirname), context.getFilename());
if (!fileRelativePath.endsWith('/')) {
fileRelativePath += '/';
}
const ruleArgs = <Record<string, string[]>>context.options[0];
const matchingKey = Object.keys(ruleArgs).find(key => fileRelativePath.startsWith(key) || minimatch(fileRelativePath, key));
if (!matchingKey) {
// nothing
return {};
}
const restrictedImports = ruleArgs[matchingKey];
return createImportRuleListener((node, path) => {
if (path[0] === '.') {
path = join(dirname(context.getFilename()), path);
}
if ((
restrictedImports.includes(path) || restrictedImports.some(restriction => minimatch(path, restriction))
) && !(
(node.parent?.type === TSESTree.AST_NODE_TYPES.ImportDeclaration && node.parent.importKind === 'type') ||
(node.parent && 'exportKind' in node.parent && node.parent.exportKind === 'type'))) { // the export could be multiple types
context.report({
loc: node.parent!.loc,
messageId: 'layerbreaker',
data: {
import: path
}
});
}
});
}
};