diff --git a/build/lib/eslint/code-import-patterns.js b/build/lib/eslint/code-import-patterns.js index dca00604b17..144f7cc9b62 100644 --- a/build/lib/eslint/code-import-patterns.js +++ b/build/lib/eslint/code-import-patterns.js @@ -5,6 +5,7 @@ *--------------------------------------------------------------------------------------------*/ const path_1 = require("path"); const minimatch = require("minimatch"); +const utils_1 = require("./utils"); module.exports = new class { constructor() { this.meta = { @@ -19,26 +20,12 @@ module.exports = new class { const configs = context.options; for (const config of configs) { if (minimatch(context.getFilename(), config.target)) { - return { - ImportDeclaration: (node) => { - this._checkImport(context, config, node, node.source.value); - }, - CallExpression: (node) => { - var _a; - const { callee, arguments: args } = node; - if (callee.type === 'Import' && ((_a = args[0]) === null || _a === void 0 ? void 0 : _a.type) === 'Literal') { - this._checkImport(context, config, node, args[0].value); - } - } - }; + return utils_1.createImportRuleListener((node, value) => this._checkImport(context, config, node, value)); } } return {}; } _checkImport(context, config, node, path) { - if (typeof path !== 'string') { - return; - } // resolve relative paths if (path[0] === '.') { path = path_1.join(context.getFilename(), path); diff --git a/build/lib/eslint/code-import-patterns.ts b/build/lib/eslint/code-import-patterns.ts index 743f4bfdc6e..eac15ebfa05 100644 --- a/build/lib/eslint/code-import-patterns.ts +++ b/build/lib/eslint/code-import-patterns.ts @@ -7,6 +7,7 @@ import * as eslint from 'eslint'; import * as estree from 'estree'; import { join } from 'path'; import * as minimatch from 'minimatch'; +import { createImportRuleListener } from './utils'; interface ImportPatternsConfig { target: string; @@ -29,28 +30,14 @@ export = new class implements eslint.Rule.RuleModule { for (const config of configs) { if (minimatch(context.getFilename(), config.target)) { - return { - ImportDeclaration: (node: estree.Node) => { - this._checkImport(context, config!, node, (node).source.value); - }, - CallExpression: (node: estree.Node) => { - const { callee, arguments: args } = node; - if ((callee.type) === 'Import' && args[0]?.type === 'Literal') { - this._checkImport(context, config!, node, (args[0]).value); - } - } - }; + return createImportRuleListener((node, value) => this._checkImport(context, config, node, value)); } } return {}; - } - private _checkImport(context: eslint.Rule.RuleContext, config: ImportPatternsConfig, node: estree.Node, path: any) { - if (typeof path !== 'string') { - return; - } + private _checkImport(context: eslint.Rule.RuleContext, config: ImportPatternsConfig, node: estree.Node, path: string) { // resolve relative paths if (path[0] === '.') { diff --git a/build/lib/eslint/code-layering.js b/build/lib/eslint/code-layering.js index 220b31f1f01..a033ca96c04 100644 --- a/build/lib/eslint/code-layering.js +++ b/build/lib/eslint/code-layering.js @@ -4,6 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ const path_1 = require("path"); +const utils_1 = require("./utils"); module.exports = new class { constructor() { this.meta = { @@ -37,45 +38,30 @@ module.exports = new class { // nothing return {}; } - return { - ImportDeclaration: (node) => { - this._checkImport(context, config, node, node.source.value); - }, - CallExpression: (node) => { - var _a; - const { callee, arguments: args } = node; - if (callee.type === 'Import' && ((_a = args[0]) === null || _a === void 0 ? void 0 : _a.type) === 'Literal') { - this._checkImport(context, config, node, args[0].value); + return utils_1.createImportRuleListener((node, path) => { + if (path[0] === '.') { + path = path_1.join(path_1.dirname(context.getFilename()), path); + } + const parts = path_1.dirname(path).split(/\\|\//); + for (let i = parts.length - 1; i >= 0; i--) { + const part = parts[i]; + if (config.allowed.has(part)) { + // GOOD - same layer + break; + } + if (config.disallowed.has(part)) { + // BAD - wrong layer + context.report({ + node, + messageId: 'layerbreaker', + data: { + from: part, + allowed: [...config.allowed.keys()].join(', ') + } + }); + break; } } - }; - } - _checkImport(context, config, node, path) { - if (typeof path !== 'string') { - return; - } - if (path[0] === '.') { - path = path_1.join(path_1.dirname(context.getFilename()), path); - } - const parts = path_1.dirname(path).split(/\\|\//); - for (let i = parts.length - 1; i >= 0; i--) { - const part = parts[i]; - if (config.allowed.has(part)) { - // GOOD - same layer - break; - } - if (config.disallowed.has(part)) { - // BAD - wrong layer - context.report({ - node, - messageId: 'layerbreaker', - data: { - from: part, - allowed: [...config.allowed.keys()].join(', ') - } - }); - break; - } - } + }); } }; diff --git a/build/lib/eslint/code-layering.ts b/build/lib/eslint/code-layering.ts index 83962de0c0a..83775e9adbd 100644 --- a/build/lib/eslint/code-layering.ts +++ b/build/lib/eslint/code-layering.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import * as eslint from 'eslint'; -import * as estree from 'estree'; import { join, dirname } from 'path'; +import { createImportRuleListener } from './utils'; type Config = { allowed: Set; @@ -49,51 +49,34 @@ export = new class implements eslint.Rule.RuleModule { return {}; } - return { - ImportDeclaration: (node: estree.Node) => { - this._checkImport(context, config!, node, (node).source.value); - }, - CallExpression: (node: estree.Node) => { - const { callee, arguments: args } = node; - if ((callee.type) === 'Import' && args[0]?.type === 'Literal') { - this._checkImport(context, config!, node, (args[0]).value); + return createImportRuleListener((node, path) => { + if (path[0] === '.') { + path = join(dirname(context.getFilename()), path); + } + + const parts = dirname(path).split(/\\|\//); + for (let i = parts.length - 1; i >= 0; i--) { + const part = parts[i]; + + if (config!.allowed.has(part)) { + // GOOD - same layer + break; + } + + if (config!.disallowed.has(part)) { + // BAD - wrong layer + context.report({ + node, + messageId: 'layerbreaker', + data: { + from: part, + allowed: [...config!.allowed.keys()].join(', ') + } + }); + break; } } - }; - } - - private _checkImport(context: eslint.Rule.RuleContext, config: Config, node: estree.Node, path: any) { - if (typeof path !== 'string') { - return; - } - - if (path[0] === '.') { - path = join(dirname(context.getFilename()), path); - } - - const parts = dirname(path).split(/\\|\//); - for (let i = parts.length - 1; i >= 0; i--) { - const part = parts[i]; - - if (config.allowed.has(part)) { - // GOOD - same layer - break; - } - - if (config.disallowed.has(part)) { - // BAD - wrong layer - context.report({ - node, - messageId: 'layerbreaker', - data: { - from: part, - allowed: [...config.allowed.keys()].join(', ') - } - }); - - break; - } - } + }); } }; diff --git a/build/lib/eslint/code-no-nls-in-standalone-editor.js b/build/lib/eslint/code-no-nls-in-standalone-editor.js index 8a13a1c8f17..176c0250a07 100644 --- a/build/lib/eslint/code-no-nls-in-standalone-editor.js +++ b/build/lib/eslint/code-no-nls-in-standalone-editor.js @@ -4,6 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ const path_1 = require("path"); +const utils_1 = require("./utils"); module.exports = new class NoNlsInStandaloneEditorRule { constructor() { this.meta = { @@ -16,39 +17,24 @@ module.exports = new class NoNlsInStandaloneEditorRule { } create(context) { const fileName = context.getFilename(); - if (!(/vs(\/|\\)editor(\/|\\)standalone(\/|\\)/.test(fileName) + if (/vs(\/|\\)editor(\/|\\)standalone(\/|\\)/.test(fileName) || /vs(\/|\\)editor(\/|\\)common(\/|\\)standalone(\/|\\)/.test(fileName) || /vs(\/|\\)editor(\/|\\)editor.api/.test(fileName) || /vs(\/|\\)editor(\/|\\)editor.main/.test(fileName) - || /vs(\/|\\)editor(\/|\\)editor.worker/.test(fileName))) { - return {}; - } - return { - ImportDeclaration: (node) => { - this._checkImport(context, node, node.source.value); - }, - CallExpression: (node) => { - var _a; - const { callee, arguments: args } = node; - if (callee.type === 'Import' && ((_a = args[0]) === null || _a === void 0 ? void 0 : _a.type) === 'Literal') { - this._checkImport(context, node, args[0].value); + || /vs(\/|\\)editor(\/|\\)editor.worker/.test(fileName)) { + return utils_1.createImportRuleListener((node, path) => { + // resolve relative paths + if (path[0] === '.') { + path = path_1.join(context.getFilename(), path); + } + if (/vs(\/|\\)nls/.test(path)) { + context.report({ + node, + messageId: 'noNls' + }); } - } - }; - } - _checkImport(context, node, path) { - if (typeof path !== 'string') { - return; - } - // resolve relative paths - if (path[0] === '.') { - path = path_1.join(context.getFilename(), path); - } - if (/vs(\/|\\)nls/.test(path)) { - context.report({ - node, - messageId: 'noNls' }); } + return {}; } }; diff --git a/build/lib/eslint/code-no-nls-in-standalone-editor.ts b/build/lib/eslint/code-no-nls-in-standalone-editor.ts index 060ce579497..4bf0495853f 100644 --- a/build/lib/eslint/code-no-nls-in-standalone-editor.ts +++ b/build/lib/eslint/code-no-nls-in-standalone-editor.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import * as eslint from 'eslint'; -import * as estree from 'estree'; import { join } from 'path'; +import { createImportRuleListener } from './utils'; export = new class NoNlsInStandaloneEditorRule implements eslint.Rule.RuleModule { @@ -20,48 +20,31 @@ export = new class NoNlsInStandaloneEditorRule implements eslint.Rule.RuleModule create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { const fileName = context.getFilename(); - if (!( + if ( /vs(\/|\\)editor(\/|\\)standalone(\/|\\)/.test(fileName) || /vs(\/|\\)editor(\/|\\)common(\/|\\)standalone(\/|\\)/.test(fileName) || /vs(\/|\\)editor(\/|\\)editor.api/.test(fileName) || /vs(\/|\\)editor(\/|\\)editor.main/.test(fileName) || /vs(\/|\\)editor(\/|\\)editor.worker/.test(fileName) - )) { - return {}; - } - - return { - ImportDeclaration: (node: estree.Node) => { - this._checkImport(context, node, (node).source.value); - }, - CallExpression: (node: estree.Node) => { - const { callee, arguments: args } = node; - if ((callee.type) === 'Import' && args[0]?.type === 'Literal') { - this._checkImport(context, node, (args[0]).value); - } - } - }; - } - - private _checkImport(context: eslint.Rule.RuleContext, node: estree.Node, path: any) { - if (typeof path !== 'string') { - return; - } - - // resolve relative paths - if (path[0] === '.') { - path = join(context.getFilename(), path); - } - - if ( - /vs(\/|\\)nls/.test(path) ) { - context.report({ - node, - messageId: 'noNls' + return createImportRuleListener((node, path) => { + // resolve relative paths + if (path[0] === '.') { + path = join(context.getFilename(), path); + } + + if ( + /vs(\/|\\)nls/.test(path) + ) { + context.report({ + node, + messageId: 'noNls' + }); + } }); } + return {}; } }; diff --git a/build/lib/eslint/code-no-standalone-editor.js b/build/lib/eslint/code-no-standalone-editor.js index 249c6a69965..576bc60f580 100644 --- a/build/lib/eslint/code-no-standalone-editor.js +++ b/build/lib/eslint/code-no-standalone-editor.js @@ -4,6 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ const path_1 = require("path"); +const utils_1 = require("./utils"); module.exports = new class NoNlsInStandaloneEditorRule { constructor() { this.meta = { @@ -19,36 +20,21 @@ module.exports = new class NoNlsInStandaloneEditorRule { // the vs/editor folder is allowed to use the standalone editor return {}; } - return { - ImportDeclaration: (node) => { - this._checkImport(context, node, node.source.value); - }, - CallExpression: (node) => { - var _a; - const { callee, arguments: args } = node; - if (callee.type === 'Import' && ((_a = args[0]) === null || _a === void 0 ? void 0 : _a.type) === 'Literal') { - this._checkImport(context, node, args[0].value); - } + return utils_1.createImportRuleListener((node, path) => { + // resolve relative paths + if (path[0] === '.') { + path = path_1.join(context.getFilename(), path); } - }; - } - _checkImport(context, node, path) { - if (typeof path !== 'string') { - return; - } - // resolve relative paths - if (path[0] === '.') { - path = path_1.join(context.getFilename(), path); - } - if (/vs(\/|\\)editor(\/|\\)standalone(\/|\\)/.test(path) - || /vs(\/|\\)editor(\/|\\)common(\/|\\)standalone(\/|\\)/.test(path) - || /vs(\/|\\)editor(\/|\\)editor.api/.test(path) - || /vs(\/|\\)editor(\/|\\)editor.main/.test(path) - || /vs(\/|\\)editor(\/|\\)editor.worker/.test(path)) { - context.report({ - node, - messageId: 'badImport' - }); - } + if (/vs(\/|\\)editor(\/|\\)standalone(\/|\\)/.test(path) + || /vs(\/|\\)editor(\/|\\)common(\/|\\)standalone(\/|\\)/.test(path) + || /vs(\/|\\)editor(\/|\\)editor.api/.test(path) + || /vs(\/|\\)editor(\/|\\)editor.main/.test(path) + || /vs(\/|\\)editor(\/|\\)editor.worker/.test(path)) { + context.report({ + node, + messageId: 'badImport' + }); + } + }); } }; diff --git a/build/lib/eslint/code-no-standalone-editor.ts b/build/lib/eslint/code-no-standalone-editor.ts index bd748663e66..5d42c826644 100644 --- a/build/lib/eslint/code-no-standalone-editor.ts +++ b/build/lib/eslint/code-no-standalone-editor.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import * as eslint from 'eslint'; -import * as estree from 'estree'; import { join } from 'path'; +import { createImportRuleListener } from './utils'; export = new class NoNlsInStandaloneEditorRule implements eslint.Rule.RuleModule { @@ -24,41 +24,26 @@ export = new class NoNlsInStandaloneEditorRule implements eslint.Rule.RuleModule return {}; } - return { - ImportDeclaration: (node: estree.Node) => { - this._checkImport(context, node, (node).source.value); - }, - CallExpression: (node: estree.Node) => { - const { callee, arguments: args } = node; - if ((callee.type) === 'Import' && args[0]?.type === 'Literal') { - this._checkImport(context, node, (args[0]).value); - } + return createImportRuleListener((node, path) => { + + // resolve relative paths + if (path[0] === '.') { + path = join(context.getFilename(), path); } - }; - } - private _checkImport(context: eslint.Rule.RuleContext, node: estree.Node, path: any) { - if (typeof path !== 'string') { - return; - } - - // resolve relative paths - if (path[0] === '.') { - path = join(context.getFilename(), path); - } - - if ( - /vs(\/|\\)editor(\/|\\)standalone(\/|\\)/.test(path) - || /vs(\/|\\)editor(\/|\\)common(\/|\\)standalone(\/|\\)/.test(path) - || /vs(\/|\\)editor(\/|\\)editor.api/.test(path) - || /vs(\/|\\)editor(\/|\\)editor.main/.test(path) - || /vs(\/|\\)editor(\/|\\)editor.worker/.test(path) - ) { - context.report({ - node, - messageId: 'badImport' - }); - } + if ( + /vs(\/|\\)editor(\/|\\)standalone(\/|\\)/.test(path) + || /vs(\/|\\)editor(\/|\\)common(\/|\\)standalone(\/|\\)/.test(path) + || /vs(\/|\\)editor(\/|\\)editor.api/.test(path) + || /vs(\/|\\)editor(\/|\\)editor.main/.test(path) + || /vs(\/|\\)editor(\/|\\)editor.worker/.test(path) + ) { + context.report({ + node, + messageId: 'badImport' + }); + } + }); } }; diff --git a/build/lib/eslint/code-translation-remind.js b/build/lib/eslint/code-translation-remind.js index a6a86d50408..1f181d88848 100644 --- a/build/lib/eslint/code-translation-remind.js +++ b/build/lib/eslint/code-translation-remind.js @@ -5,6 +5,7 @@ *--------------------------------------------------------------------------------------------*/ var _a; const fs_1 = require("fs"); +const utils_1 = require("./utils"); module.exports = new (_a = class TranslationRemind { constructor() { this.meta = { @@ -16,51 +17,41 @@ module.exports = new (_a = class TranslationRemind { }; } create(context) { - return { - ImportDeclaration: (node) => { - this._checkImport(context, node, node.source.value); - }, - CallExpression: (node) => { - var _a; - const { callee, arguments: args } = node; - if (callee.type === 'Import' && ((_a = args[0]) === null || _a === void 0 ? void 0 : _a.type) === 'Literal') { - this._checkImport(context, node, args[0].value); - } - } - }; + return utils_1.createImportRuleListener((node, path) => this._checkImport(context, node, path)); } _checkImport(context, node, path) { - if (path === TranslationRemind.NLS_MODULE) { - const currentFile = context.getFilename(); - const matchService = currentFile.match(/vs\/workbench\/services\/\w+/); - const matchPart = currentFile.match(/vs\/workbench\/contrib\/\w+/); - if (!matchService && !matchPart) { + if (path !== TranslationRemind.NLS_MODULE) { + return; + } + const currentFile = context.getFilename(); + const matchService = currentFile.match(/vs\/workbench\/services\/\w+/); + const matchPart = currentFile.match(/vs\/workbench\/contrib\/\w+/); + if (!matchService && !matchPart) { + return; + } + const resource = matchService ? matchService[0] : matchPart[0]; + let resourceDefined = false; + let json; + try { + json = fs_1.readFileSync('./build/lib/i18n.resources.json', 'utf8'); + } + catch (e) { + console.error('[translation-remind rule]: File with resources to pull from Transifex was not found. Aborting translation resource check for newly defined workbench part/service.'); + return; + } + const workbenchResources = JSON.parse(json).workbench; + workbenchResources.forEach((existingResource) => { + if (existingResource.name === resource) { + resourceDefined = true; return; } - const resource = matchService ? matchService[0] : matchPart[0]; - let resourceDefined = false; - let json; - try { - json = fs_1.readFileSync('./build/lib/i18n.resources.json', 'utf8'); - } - catch (e) { - console.error('[translation-remind rule]: File with resources to pull from Transifex was not found. Aborting translation resource check for newly defined workbench part/service.'); - return; - } - const workbenchResources = JSON.parse(json).workbench; - workbenchResources.forEach((existingResource) => { - if (existingResource.name === resource) { - resourceDefined = true; - return; - } + }); + if (!resourceDefined) { + context.report({ + node, + messageId: 'missing', + data: { resource } }); - if (!resourceDefined) { - context.report({ - node, - messageId: 'missing', - data: { resource } - }); - } } } }, diff --git a/build/lib/eslint/code-translation-remind.ts b/build/lib/eslint/code-translation-remind.ts index 5af5a8a2195..a95840c86f8 100644 --- a/build/lib/eslint/code-translation-remind.ts +++ b/build/lib/eslint/code-translation-remind.ts @@ -6,6 +6,7 @@ import * as eslint from 'eslint'; import * as estree from 'estree'; import { readFileSync } from 'fs'; +import { createImportRuleListener } from './utils'; export = new class TranslationRemind implements eslint.Rule.RuleModule { @@ -21,59 +22,48 @@ export = new class TranslationRemind implements eslint.Rule.RuleModule { }; create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { - - return { - ImportDeclaration: (node: estree.Node) => { - this._checkImport(context, node, (node).source.value); - }, - CallExpression: (node: estree.Node) => { - const { callee, arguments: args } = node; - if ((callee.type) === 'Import' && args[0]?.type === 'Literal') { - this._checkImport(context, node, (args[0]).value); - } - } - }; + return createImportRuleListener((node, path) => this._checkImport(context, node, path)); } - private _checkImport(context: eslint.Rule.RuleContext, node: estree.Node, path: any) { + private _checkImport(context: eslint.Rule.RuleContext, node: estree.Node, path: string) { - if (path === TranslationRemind.NLS_MODULE) { - - const currentFile = context.getFilename(); - const matchService = currentFile.match(/vs\/workbench\/services\/\w+/); - const matchPart = currentFile.match(/vs\/workbench\/contrib\/\w+/); - if (!matchService && !matchPart) { - return; - } - - const resource = matchService ? matchService[0] : matchPart![0]; - let resourceDefined = false; - - let json; - try { - json = readFileSync('./build/lib/i18n.resources.json', 'utf8'); - } catch (e) { - console.error('[translation-remind rule]: File with resources to pull from Transifex was not found. Aborting translation resource check for newly defined workbench part/service.'); - return; - } - const workbenchResources = JSON.parse(json).workbench; - - workbenchResources.forEach((existingResource: any) => { - if (existingResource.name === resource) { - resourceDefined = true; - return; - } - }); - - if (!resourceDefined) { - context.report({ - node, - messageId: 'missing', - data: { resource } - }); - } + if (path !== TranslationRemind.NLS_MODULE) { + return; } + const currentFile = context.getFilename(); + const matchService = currentFile.match(/vs\/workbench\/services\/\w+/); + const matchPart = currentFile.match(/vs\/workbench\/contrib\/\w+/); + if (!matchService && !matchPart) { + return; + } + + const resource = matchService ? matchService[0] : matchPart![0]; + let resourceDefined = false; + + let json; + try { + json = readFileSync('./build/lib/i18n.resources.json', 'utf8'); + } catch (e) { + console.error('[translation-remind rule]: File with resources to pull from Transifex was not found. Aborting translation resource check for newly defined workbench part/service.'); + return; + } + const workbenchResources = JSON.parse(json).workbench; + + workbenchResources.forEach((existingResource: any) => { + if (existingResource.name === resource) { + resourceDefined = true; + return; + } + }); + + if (!resourceDefined) { + context.report({ + node, + messageId: 'missing', + data: { resource } + }); + } } }; diff --git a/build/lib/eslint/utils.js b/build/lib/eslint/utils.js new file mode 100644 index 00000000000..8730958c8e7 --- /dev/null +++ b/build/lib/eslint/utils.js @@ -0,0 +1,36 @@ +"use strict"; +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +Object.defineProperty(exports, "__esModule", { value: true }); +function createImportRuleListener(validateImport) { + function _checkImport(node) { + if (node && node.type === 'Literal' && typeof node.value === 'string') { + validateImport(node, node.value); + } + } + return { + // import ??? from 'module' + ImportDeclaration: (node) => { + _checkImport(node.source); + }, + // import('module').then(...) + CallExpression: (node) => { + var _a; + const { callee, arguments: args } = node; + if (callee.type === 'Import' && ((_a = args[0]) === null || _a === void 0 ? void 0 : _a.type) === 'Literal') { + _checkImport(args[0]); + } + }, + // export ?? from 'module' + ExportAllDeclaration: (node) => { + _checkImport(node.source); + }, + // export {foo} from 'module' + ExportNamedDeclaration: (node) => { + _checkImport(node.source); + } + }; +} +exports.createImportRuleListener = createImportRuleListener; diff --git a/build/lib/eslint/utils.ts b/build/lib/eslint/utils.ts new file mode 100644 index 00000000000..42da8c4b78d --- /dev/null +++ b/build/lib/eslint/utils.ts @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as eslint from 'eslint'; +import * as estree from 'estree'; + +//https://github.com/estree/estree/blob/master/es2015.md#exportnameddeclaration +declare interface ExportNamedDeclaration { + type: "ExportNamedDeclaration"; + declaration: estree.Declaration | null; + specifiers: [estree.ExportSpecifier]; + source: estree.Literal | null; +} + +export function createImportRuleListener(validateImport: (node: estree.SimpleLiteral, value: string) => any): eslint.Rule.RuleListener { + + function _checkImport(node: estree.Literal | null) { + if (node && node.type === 'Literal' && typeof node.value === 'string') { + validateImport(node, node.value); + } + } + + return { + // import ??? from 'module' + ImportDeclaration: (node: estree.Node) => { + _checkImport((node).source); + }, + // import('module').then(...) + CallExpression: (node: estree.Node) => { + const { callee, arguments: args } = node; + if ((callee.type) === 'Import' && args[0]?.type === 'Literal') { + _checkImport(args[0]); + } + }, + // export ?? from 'module' + ExportAllDeclaration: (node: estree.Node) => { + _checkImport((node).source); + }, + // export {foo} from 'module' + ExportNamedDeclaration: (node: estree.Node) => { + _checkImport((node).source); + } + }; +}