Path: blob/main/tests/src/rules/extensions.js
829 views
import { RuleTester } from 'eslint';1import rule from 'rules/extensions';2import { getTSParsers, test, testFilePath } from '../utils';34const ruleTester = new RuleTester();56ruleTester.run('extensions', rule, {7valid: [8test({ code: 'import a from "@/a"' }),9test({ code: 'import a from "a"' }),10test({ code: 'import dot from "./file.with.dot"' }),11test({12code: 'import a from "a/index.js"',13options: [ 'always' ],14}),15test({16code: 'import dot from "./file.with.dot.js"',17options: [ 'always' ],18}),19test({20code: [21'import a from "a"',22'import packageConfig from "./package.json"',23].join('\n'),24options: [ { json: 'always', js: 'never' } ],25}),26test({27code: [28'import lib from "./bar"',29'import component from "./bar.jsx"',30'import data from "./bar.json"',31].join('\n'),32options: [ 'never' ],33settings: { 'import/resolve': { 'extensions': [ '.js', '.jsx', '.json' ] } },34}),3536test({37code: [38'import bar from "./bar"',39'import barjson from "./bar.json"',40'import barhbs from "./bar.hbs"',41].join('\n'),42options: [ 'always', { js: 'never', jsx: 'never' } ],43settings: { 'import/resolve': { 'extensions': [ '.js', '.jsx', '.json', '.hbs' ] } },44}),4546test({47code: [48'import bar from "./bar.js"',49'import pack from "./package"',50].join('\n'),51options: [ 'never', { js: 'always', json: 'never' } ],52settings: { 'import/resolve': { 'extensions': [ '.js', '.json' ] } },53}),5455// unresolved (#271/#295)56test({ code: 'import path from "path"' }),57test({ code: 'import path from "path"', options: [ 'never' ] }),58test({ code: 'import path from "path"', options: [ 'always' ] }),59test({ code: 'import thing from "./fake-file.js"', options: [ 'always' ] }),60test({ code: 'import thing from "non-package"', options: [ 'never' ] }),6162test({63code: `64import foo from './foo.js'65import bar from './bar.json'66import Component from './Component.jsx'67import express from 'express'68`,69options: [ 'ignorePackages' ],70}),7172test({73code: `74import foo from './foo.js'75import bar from './bar.json'76import Component from './Component.jsx'77import express from 'express'78`,79options: [ 'always', { ignorePackages: true } ],80}),8182test({83code: `84import foo from './foo'85import bar from './bar'86import Component from './Component'87import express from 'express'88`,89options: [ 'never', { ignorePackages: true } ],90}),9192test({93code: 'import exceljs from "exceljs"',94options: [ 'always', { js: 'never', jsx: 'never' } ],95filename: testFilePath('./internal-modules/plugins/plugin.js'),96settings: {97'import/resolver': {98'node': { 'extensions': [ '.js', '.jsx', '.json' ] },99'webpack': { 'config': 'webpack.empty.config.js' },100},101},102}),103104// export (#964)105test({106code: [107'export { foo } from "./foo.js"',108'let bar; export { bar }',109].join('\n'),110options: [ 'always' ],111}),112test({113code: [114'export { foo } from "./foo"',115'let bar; export { bar }',116].join('\n'),117options: [ 'never' ],118}),119120// Root packages should be ignored and they are names not files121test({122code: [123'import lib from "pkg.js"',124'import lib2 from "pgk/package"',125'import lib3 from "@name/pkg.js"',126].join('\n'),127options: [ 'never' ],128}),129130// Query strings.131test({132code: 'import bare from "./foo?a=True.ext"',133options: [ 'never' ],134}),135test({136code: 'import bare from "./foo.js?a=True"',137options: [ 'always' ],138}),139140test({141code: [142'import lib from "pkg"',143'import lib2 from "pgk/package.js"',144'import lib3 from "@name/pkg"',145].join('\n'),146options: [ 'always' ],147}),148],149150invalid: [151test({152code: 'import a from "a/index.js"',153errors: [ {154message: 'Unexpected use of file extension "js" for "a/index.js"',155line: 1,156column: 15,157} ],158}),159test({160code: 'import dot from "./file.with.dot"',161options: [ 'always' ],162errors: [163{164message: 'Missing file extension "js" for "./file.with.dot"',165line: 1,166column: 17,167},168],169}),170test({171code: [172'import a from "a/index.js"',173'import packageConfig from "./package"',174].join('\n'),175options: [ { json: 'always', js: 'never' } ],176settings: { 'import/resolve': { 'extensions': [ '.js', '.json' ] } },177errors: [178{179message: 'Unexpected use of file extension "js" for "a/index.js"',180line: 1,181column: 15,182},183{184message: 'Missing file extension "json" for "./package"',185line: 2,186column: 27,187},188],189}),190test({191code: [192'import lib from "./bar.js"',193'import component from "./bar.jsx"',194'import data from "./bar.json"',195].join('\n'),196options: [ 'never' ],197settings: { 'import/resolve': { 'extensions': [ '.js', '.jsx', '.json' ] } },198errors: [199{200message: 'Unexpected use of file extension "js" for "./bar.js"',201line: 1,202column: 17,203},204],205}),206test({207code: [208'import lib from "./bar.js"',209'import component from "./bar.jsx"',210'import data from "./bar.json"',211].join('\n'),212options: [ { json: 'always', js: 'never', jsx: 'never' } ],213settings: { 'import/resolve': { 'extensions': [ '.js', '.jsx', '.json' ] } },214errors: [215{216message: 'Unexpected use of file extension "js" for "./bar.js"',217line: 1,218column: 17,219},220],221}),222// extension resolve order (#583/#965)223test({224code: [225'import component from "./bar.jsx"',226'import data from "./bar.json"',227].join('\n'),228options: [ { json: 'always', js: 'never', jsx: 'never' } ],229settings: { 'import/resolve': { 'extensions': [ '.jsx', '.json', '.js' ] } },230errors: [231{232message: 'Unexpected use of file extension "jsx" for "./bar.jsx"',233line: 1,234column: 23,235},236],237}),238test({239code: 'import "./bar.coffee"',240errors: [241{242message: 'Unexpected use of file extension "coffee" for "./bar.coffee"',243line: 1,244column: 8,245},246],247options: ['never', { js: 'always', jsx: 'always' }],248settings: { 'import/resolve': { 'extensions': ['.coffee', '.js'] } },249}),250251test({252code: [253'import barjs from "./bar.js"',254'import barjson from "./bar.json"',255'import barnone from "./bar"',256].join('\n'),257options: [ 'always', { json: 'always', js: 'never', jsx: 'never' } ],258settings: { 'import/resolve': { 'extensions': [ '.js', '.jsx', '.json' ] } },259errors: [260{261message: 'Unexpected use of file extension "js" for "./bar.js"',262line: 1,263column: 19,264},265],266}),267268test({269code: [270'import barjs from "./bar.js"',271'import barjson from "./bar.json"',272'import barnone from "./bar"',273].join('\n'),274options: [ 'never', { json: 'always', js: 'never', jsx: 'never' } ],275settings: { 'import/resolve': { 'extensions': [ '.js', '.jsx', '.json' ] } },276errors: [277{278message: 'Unexpected use of file extension "js" for "./bar.js"',279line: 1,280column: 19,281},282],283}),284285// unresolved (#271/#295)286test({287code: 'import thing from "./fake-file.js"',288options: [ 'never' ],289errors: [290{291message: 'Unexpected use of file extension "js" for "./fake-file.js"',292line: 1,293column: 19,294},295],296}),297test({298code: 'import thing from "non-package/test"',299options: [ 'always' ],300errors: [301{302message: 'Missing file extension for "non-package/test"',303line: 1,304column: 19,305},306],307}),308309test({310code: 'import thing from "@name/pkg/test"',311options: [ 'always' ],312errors: [313{314message: 'Missing file extension for "@name/pkg/test"',315line: 1,316column: 19,317},318],319}),320321test({322code: 'import thing from "@name/pkg/test.js"',323options: [ 'never' ],324errors: [325{326message: 'Unexpected use of file extension "js" for "@name/pkg/test.js"',327line: 1,328column: 19,329},330],331}),332333334test({335code: `336import foo from './foo.js'337import bar from './bar.json'338import Component from './Component'339import baz from 'foo/baz'340import baw from '@scoped/baw/import'341import chart from '@/configs/chart'342import express from 'express'343`,344options: [ 'always', { ignorePackages: true } ],345errors: [346{347message: 'Missing file extension for "./Component"',348line: 4,349column: 31,350},351{352message: 'Missing file extension for "@/configs/chart"',353line: 7,354column: 27,355},356],357}),358359test({360code: `361import foo from './foo.js'362import bar from './bar.json'363import Component from './Component'364import baz from 'foo/baz'365import baw from '@scoped/baw/import'366import chart from '@/configs/chart'367import express from 'express'368`,369options: [ 'ignorePackages' ],370errors: [371{372message: 'Missing file extension for "./Component"',373line: 4,374column: 31,375},376{377message: 'Missing file extension for "@/configs/chart"',378line: 7,379column: 27,380},381],382}),383384test({385code: `386import foo from './foo.js'387import bar from './bar.json'388import Component from './Component.jsx'389import express from 'express'390`,391errors: [392{393message: 'Unexpected use of file extension "js" for "./foo.js"',394line: 2,395column: 25,396}, {397message: 'Unexpected use of file extension "jsx" for "./Component.jsx"',398line: 4,399column: 31,400},401],402options: [ 'never', { ignorePackages: true } ],403}),404405test({406code: `407import foo from './foo.js'408import bar from './bar.json'409import Component from './Component.jsx'410`,411errors: [412{413message: 'Unexpected use of file extension "jsx" for "./Component.jsx"',414line: 4,415column: 31,416},417],418options: [ 'always', { pattern: { jsx: 'never' } } ],419}),420421// export (#964)422test({423code: [424'export { foo } from "./foo"',425'let bar; export { bar }',426].join('\n'),427options: [ 'always' ],428errors: [429{430message: 'Missing file extension for "./foo"',431line: 1,432column: 21,433},434],435}),436test({437code: [438'export { foo } from "./foo.js"',439'let bar; export { bar }',440].join('\n'),441options: [ 'never' ],442errors: [443{444message: 'Unexpected use of file extension "js" for "./foo.js"',445line: 1,446column: 21,447},448],449}),450451// Query strings.452test({453code: 'import withExtension from "./foo.js?a=True"',454options: [ 'never' ],455errors: [456{457message: 'Unexpected use of file extension "js" for "./foo.js?a=True"',458line: 1,459column: 27,460},461],462}),463test({464code: 'import withoutExtension from "./foo?a=True.ext"',465options: [ 'always' ],466errors: [467{468message: 'Missing file extension for "./foo?a=True.ext"',469line: 1,470column: 30,471},472],473}),474// require (#1230)475test({476code: [477'const { foo } = require("./foo")',478'export { foo }',479].join('\n'),480options: [ 'always' ],481errors: [482{483message: 'Missing file extension for "./foo"',484line: 1,485column: 25,486},487],488}),489test({490code: [491'const { foo } = require("./foo.js")',492'export { foo }',493].join('\n'),494options: [ 'never' ],495errors: [496{497message: 'Unexpected use of file extension "js" for "./foo.js"',498line: 1,499column: 25,500},501],502}),503504// export { } from505test({506code: 'export { foo } from "./foo"',507options: [ 'always' ],508errors: [509{510message: 'Missing file extension for "./foo"',511line: 1,512column: 21,513},514],515}),516test({517code: `518import foo from "@/ImNotAScopedModule";519import chart from '@/configs/chart';520`,521options: ['always'],522errors: [523{524message: 'Missing file extension for "@/ImNotAScopedModule"',525line: 2,526},527{528message: 'Missing file extension for "@/configs/chart"',529line: 3,530},531],532}),533test({534code: 'export { foo } from "./foo.js"',535options: [ 'never' ],536errors: [537{538message: 'Unexpected use of file extension "js" for "./foo.js"',539line: 1,540column: 21,541},542],543}),544545// export * from546test({547code: 'export * from "./foo"',548options: [ 'always' ],549errors: [550{551message: 'Missing file extension for "./foo"',552line: 1,553column: 15,554},555],556}),557test({558code: 'export * from "./foo.js"',559options: [ 'never' ],560errors: [561{562message: 'Unexpected use of file extension "js" for "./foo.js"',563line: 1,564column: 15,565},566],567}),568test({569code: 'import foo from "@/ImNotAScopedModule.js"',570options: ['never'],571errors: [572{573message: 'Unexpected use of file extension "js" for "@/ImNotAScopedModule.js"',574line: 1,575},576],577}),578test({579code: `580import _ from 'lodash';581import m from '@test-scope/some-module/index.js';582583import bar from './bar';584`,585options: ['never'],586settings: {587'import/resolver': 'webpack',588'import/external-module-folders': ['node_modules', 'symlinked-module'],589},590errors: [591{592message: 'Unexpected use of file extension "js" for "@test-scope/some-module/index.js"',593line: 3,594},595],596}),597],598});599600describe('TypeScript', () => {601getTSParsers()602// Type-only imports were added in TypeScript ESTree 2.23.0603.filter((parser) => parser !== require.resolve('typescript-eslint-parser'))604.forEach((parser) => {605ruleTester.run(`${parser}: extensions ignore type-only`, rule, {606valid: [607test({608code: 'import type T from "./typescript-declare";',609options: [610'always',611{ ts: 'never', tsx: 'never', js: 'never', jsx: 'never' },612],613parser,614}),615],616invalid: [617test({618code: 'import T from "./typescript-declare";',619errors: ['Missing file extension for "./typescript-declare"'],620options: [621'always',622{ ts: 'never', tsx: 'never', js: 'never', jsx: 'never' },623],624parser,625}),626],627});628});629});630631632