Path: blob/main/tests/src/rules/namespace.js
829 views
import { test, SYNTAX_CASES, getTSParsers, testVersion, testFilePath } from '../utils';1import { RuleTester } from 'eslint';2import flatMap from 'array.prototype.flatmap';34const ruleTester = new RuleTester({ env: { es6: true } });5const rule = require('rules/namespace');678function error(name, namespace) {9return { message: `'${name}' not found in imported namespace '${namespace}'.` };10}1112const valid = [13test({ code: 'import "./malformed.js"' }),1415test({ code: "import * as foo from './empty-folder';" }),16test({ code: 'import * as names from "./named-exports"; ' +17'console.log((names.b).c); ' }),1819test({ code: 'import * as names from "./named-exports"; ' +20'console.log(names.a);' }),21test({ code: 'import * as names from "./re-export-names"; ' +22'console.log(names.foo);' }),23test({24code: "import * as elements from './jsx';",25parserOptions: {26sourceType: 'module',27ecmaFeatures: { jsx: true },28ecmaVersion: 2015,29},30}),31test({ code: "import * as foo from './common';" }),3233// destructuring namespaces34test({ code: 'import * as names from "./named-exports";' +35'const { a } = names' }),36test({ code: 'import * as names from "./named-exports";' +37'const { d: c } = names' }),38test({ code: 'import * as names from "./named-exports";' +39'const { c } = foo\n' +40' , { length } = "names"\n' +41' , alt = names' }),42// deep destructuring only cares about top level43test({ code: 'import * as names from "./named-exports";' +44'const { ExportedClass: { length } } = names' }),4546// detect scope redefinition47test({ code: 'import * as names from "./named-exports";' +48'function b(names) { const { c } = names }' }),49test({ code: 'import * as names from "./named-exports";' +50'function b() { let names = null; const { c } = names }' }),51test({ code: 'import * as names from "./named-exports";' +52'const x = function names() { const { c } = names }' }),535455/////////56// es7 //57/////////58test({ code: 'export * as names from "./named-exports"',59parser: require.resolve('babel-eslint') }),60test({ code: 'export defport, * as names from "./named-exports"',61parser: require.resolve('babel-eslint') }),62// non-existent is handled by no-unresolved63test({ code: 'export * as names from "./does-not-exist"',64parser: require.resolve('babel-eslint') }),6566test({67code: 'import * as Endpoints from "./issue-195/Endpoints"; console.log(Endpoints.Users)',68parser: require.resolve('babel-eslint'),69}),7071// respect hoisting72test({73code:74'function x() { console.log((names.b).c); } ' +75'import * as names from "./named-exports"; ',76}),7778// names.default is valid export79test({ code: "import * as names from './default-export';" }),80test({ code: "import * as names from './default-export'; console.log(names.default)" }),81test({82code: 'export * as names from "./default-export"',83parser: require.resolve('babel-eslint'),84}),85test({86code: 'export defport, * as names from "./default-export"',87parser: require.resolve('babel-eslint'),88}),8990// #456: optionally ignore computed references91test({92code: `import * as names from './named-exports'; console.log(names['a']);`,93options: [{ allowComputed: true }],94}),9596// #656: should handle object-rest properties97test({98code: `import * as names from './named-exports'; const {a, b, ...rest} = names;`,99parserOptions: {100ecmaVersion: 2018,101},102}),103test({104code: `import * as names from './named-exports'; const {a, b, ...rest} = names;`,105parser: require.resolve('babel-eslint'),106}),107108// #1144: should handle re-export CommonJS as namespace109test({110code: `import * as ns from './re-export-common'; const {foo} = ns;`,111}),112113// JSX114test({115code: 'import * as Names from "./named-exports"; const Foo = <Names.a/>',116parserOptions: {117ecmaFeatures: {118jsx: true,119},120},121}),122123// Typescript124...flatMap(getTSParsers(), (parser) => [125test({126code: `127import * as foo from "./typescript-declare-nested"128foo.bar.MyFunction()129`,130parser,131settings: {132'import/parsers': { [parser]: ['.ts'] },133'import/resolver': { 'eslint-import-resolver-typescript': true },134},135}),136137test({138code: `import { foobar } from "./typescript-declare-interface"`,139parser,140settings: {141'import/parsers': { [parser]: ['.ts'] },142'import/resolver': { 'eslint-import-resolver-typescript': true },143},144}),145146test({147code: 'export * from "typescript/lib/typescript.d"',148parser,149settings: {150'import/parsers': { [parser]: ['.ts'] },151'import/resolver': { 'eslint-import-resolver-typescript': true },152},153}),154155test({156code: 'export = function name() {}',157parser,158settings: {159'import/parsers': { [parser]: ['.ts'] },160'import/resolver': { 'eslint-import-resolver-typescript': true },161},162}),163]),164165...SYNTAX_CASES,166167test({168code: `169import * as color from './color';170export const getBackgroundFromColor = (color) => color.bg;171export const getExampleColor = () => color.example172`,173}),174175...[].concat(testVersion('>= 6', () => ({176code: `177import * as middle from './middle';178179console.log(middle.myName);180`,181filename: testFilePath('export-star-2/downstream.js'),182parserOptions: {183ecmaVersion: 2020,184},185})) || []),186];187188const invalid = [189test({ code: "import * as names from './named-exports'; " +190' console.log(names.c);',191errors: [error('c', 'names')] }),192193test({ code: "import * as names from './named-exports';" +194" console.log(names['a']);",195errors: ["Unable to validate computed reference to imported namespace 'names'."] }),196197// assignment warning (from no-reassign)198test({ code: 'import * as foo from \'./bar\'; foo.foo = \'y\';',199errors: [{ message: 'Assignment to member of namespace \'foo\'.' }] }),200test({ code: 'import * as foo from \'./bar\'; foo.x = \'y\';',201errors: ['Assignment to member of namespace \'foo\'.', "'x' not found in imported namespace 'foo'."] }),202203// invalid destructuring204test({205code: 'import * as names from "./named-exports"; const { c } = names',206errors: [{ type: 'Property', message: "'c' not found in imported namespace 'names'." }],207}),208test({209code: 'import * as names from "./named-exports"; function b() { const { c } = names }',210errors: [{ type: 'Property', message: "'c' not found in imported namespace 'names'." }],211}),212test({213code: 'import * as names from "./named-exports"; const { c: d } = names',214errors: [{ type: 'Property', message: "'c' not found in imported namespace 'names'." }],215}),216test({217code: 'import * as names from "./named-exports";' +218'const { c: { d } } = names',219errors: [{ type: 'Property', message: "'c' not found in imported namespace 'names'." }],220}),221222/////////223// es7 //224/////////225226test({227code: 'import * as Endpoints from "./issue-195/Endpoints"; console.log(Endpoints.Foo)',228parser: require.resolve('babel-eslint'),229errors: ["'Foo' not found in imported namespace 'Endpoints'."],230}),231232// parse errors233test({234code: "import * as namespace from './malformed.js';",235errors: [{236message: "Parse errors in imported module './malformed.js': 'return' outside of function (1:1)",237type: 'Literal',238}],239}),240241test({242code: "import b from './deep/default'; console.log(b.e)",243errors: [ "'e' not found in imported namespace 'b'." ],244}),245246// respect hoisting247test({248code:249'console.log(names.c);' +250"import * as names from './named-exports'; ",251errors: [error('c', 'names')],252}),253test({254code:255'function x() { console.log(names.c) } ' +256"import * as names from './named-exports'; ",257errors: [error('c', 'names')],258}),259260// #328: * exports do not include default261test({262code: 'import * as ree from "./re-export"; console.log(ree.default)',263errors: [`'default' not found in imported namespace 'ree'.`],264}),265266// JSX267test({268code: 'import * as Names from "./named-exports"; const Foo = <Names.e/>',269errors: [error('e', 'Names')],270parserOptions: {271ecmaFeatures: {272jsx: true,273},274},275}),276277]278279///////////////////////280// deep dereferences //281//////////////////////282;[['deep', require.resolve('espree')], ['deep-es7', require.resolve('babel-eslint')]].forEach(function ([folder, parser]) { // close over params283valid.push(284test({ parser, code: `import * as a from "./${folder}/a"; console.log(a.b.c.d.e)` }),285test({ parser, code: `import { b } from "./${folder}/a"; console.log(b.c.d.e)` }),286test({ parser, code: `import * as a from "./${folder}/a"; console.log(a.b.c.d.e.f)` }),287test({ parser, code: `import * as a from "./${folder}/a"; var {b:{c:{d:{e}}}} = a` }),288test({ parser, code: `import { b } from "./${folder}/a"; var {c:{d:{e}}} = b` }));289290// deep namespaces should include explicitly exported defaults291test({ parser, code: `import * as a from "./${folder}/a"; console.log(a.b.default)` }),292293invalid.push(294test({295parser,296code: `import * as a from "./${folder}/a"; console.log(a.b.e)`,297errors: [ "'e' not found in deeply imported namespace 'a.b'." ],298}),299test({300parser,301code: `import { b } from "./${folder}/a"; console.log(b.e)`,302errors: [ "'e' not found in imported namespace 'b'." ],303}),304test({305parser,306code: `import * as a from "./${folder}/a"; console.log(a.b.c.e)`,307errors: [ "'e' not found in deeply imported namespace 'a.b.c'." ],308}),309test({310parser,311code: `import { b } from "./${folder}/a"; console.log(b.c.e)`,312errors: [ "'e' not found in deeply imported namespace 'b.c'." ],313}),314test({315parser,316code: `import * as a from "./${folder}/a"; var {b:{ e }} = a`,317errors: [ "'e' not found in deeply imported namespace 'a.b'." ],318}),319test({320parser,321code: `import * as a from "./${folder}/a"; var {b:{c:{ e }}} = a`,322errors: [ "'e' not found in deeply imported namespace 'a.b.c'." ],323}));324});325326ruleTester.run('namespace', rule, { valid, invalid });327328329