diff --git a/.gitignore b/.gitignore index a6fd35e1..6987c06e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ coverage .logs npm-debug.log .vscode -.DS_Store \ No newline at end of file +.DS_Store +yarn.lock \ No newline at end of file diff --git a/README.md b/README.md index 5b065855..62b3f2ac 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ EggLoader can easily load files or directories in your [egg] project. In additio - {String} baseDir - current directory of application - {Object} app - instance of egg application - {Object} plugins - merge plugins for test +- {Boolean} typescript - whether support typescript - {Logger} logger - logger instance,default is console ### High Level APIs @@ -226,7 +227,8 @@ Param | Type | Description -------------- | -------------- | ------------------------ directory | `String/Array` | directories to be loaded target | `Object` | attach the target object from loaded files -match | `String/Array` | match the files when load, default to `**/*.js` +match | `String/Array` | match the files when load, default to `**/*.js`(if typescript was true, default to `[ '**/*.(js|ts)', '!**/*.d.ts' ]`) +typescript | `Boolean` | whether support typescript ignore | `String/Array` | ignore the files when load initializer | `Function` | custom file exports, receive two parameters, first is the inject object(if not js file, will be content buffer), second is an `options` object that contain `path` caseStyle | `String/Function` | set property's case when converting a filepath to property list. diff --git a/lib/egg.js b/lib/egg.js index f8f0ddbf..49172e99 100644 --- a/lib/egg.js +++ b/lib/egg.js @@ -28,6 +28,7 @@ class EggCore extends KoaApplication { * @param {Object} options - options * @param {String} [options.baseDir=process.cwd()] - the directory of application * @param {String} [options.type=application|agent] - whether it's running in app worker or agent worker + * @param {Boolean} [options.typescript] - whether support typescript * @param {Object} [options.plugins] - custom plugins * @since 1.0.0 */ @@ -119,6 +120,7 @@ class EggCore extends KoaApplication { baseDir: options.baseDir, app: this, plugins: options.plugins, + typescript: options.typescript, logger: this.console, serverScope: options.serverScope, }); diff --git a/lib/loader/egg_loader.js b/lib/loader/egg_loader.js index 50690180..753ac112 100644 --- a/lib/loader/egg_loader.js +++ b/lib/loader/egg_loader.js @@ -18,6 +18,7 @@ class EggLoader { * @constructor * @param {Object} options - options * @param {String} options.baseDir - the directory of application + * @param {Boolean} options.typescript - whether support typescript * @param {EggCore} options.app - Application instance * @param {Logger} options.logger - logger * @param {Object} [options.plugins] - custom plugins @@ -282,7 +283,7 @@ class EggLoader { * @since 1.0.0 */ loadFile(filepath, ...inject) { - if (!fs.existsSync(filepath)) { + if (!filepath || !fs.existsSync(filepath)) { return null; } @@ -354,6 +355,7 @@ class EggLoader { directory, target, inject: this.app, + typescript: this.options.typescript, }, opt); new FileLoader(opt).load(); } @@ -370,6 +372,7 @@ class EggLoader { directory, property, inject: this.app, + typescript: this.options.typescript, }, opt); new ContextLoader(opt).load(); } @@ -391,14 +394,29 @@ class EggLoader { } getTypeFiles(filename) { - const files = [ `${filename}.default.js` ]; - if (this.serverScope) files.push(`${filename}.${this.serverScope}.js`); + const files = [ `${filename}.default` ]; + if (this.serverScope) files.push(`${filename}.${this.serverScope}`); if (this.serverEnv === 'default') return files; - files.push(`${filename}.${this.serverEnv}.js`); - if (this.serverScope) files.push(`${filename}.${this.serverScope}_${this.serverEnv}.js`); + files.push(`${filename}.${this.serverEnv}`); + if (this.serverScope) files.push(`${filename}.${this.serverScope}_${this.serverEnv}`); return files; } + + resolveModule(filepath) { + let fullPath; + try { + fullPath = require.resolve(filepath); + } catch (e) { + return undefined; + } + + if (!this.options.typescript && fullPath.endsWith('.ts')) { + return undefined; + } + + return fullPath; + } } /** diff --git a/lib/loader/file_loader.js b/lib/loader/file_loader.js index f51b4b06..36f258af 100644 --- a/lib/loader/file_loader.js +++ b/lib/loader/file_loader.js @@ -15,6 +15,7 @@ const defaults = { directory: null, target: null, match: undefined, + typescript: false, ignore: undefined, lowercaseFirst: false, caseStyle: 'camel', @@ -37,6 +38,7 @@ class FileLoader { * @param {String|Array} options.directory - directories to be loaded * @param {Object} options.target - attach the target object from loaded files * @param {String} options.match - match the files when load, support glob, default to all js files + * @param {Boolean} options.typescript - whether support typescript, default to false * @param {String} options.ignore - ignore the files when load, support glob * @param {Function} options.initializer - custom file exports, receive two parameters, first is the inject object(if not js file, will be content buffer), second is an `options` object that contain `path` * @param {Boolean} options.call - determine whether invoke when exports is function @@ -48,6 +50,9 @@ class FileLoader { constructor(options) { assert(options.directory, 'options.directory is required'); assert(options.target, 'options.target is required'); + if (options.typescript) { + assert(require.extensions['.ts'], '`require.extensions` should contains `.ts` while `options.typescript` was true'); + } this.options = Object.assign({}, defaults, options); // compatible old options _lowercaseFirst_ @@ -120,8 +125,14 @@ class FileLoader { * @since 1.0.0 */ parse() { - let files = this.options.match || [ '**/*.js' ]; - files = Array.isArray(files) ? files : [ files ]; + let files = this.options.match; + if (!files) { + files = this.options.typescript + ? [ '**/*.(js|ts)', '!**/*.d.ts' ] + : [ '**/*.js' ]; + } else { + files = Array.isArray(files) ? files : [ files ]; + } let ignore = this.options.ignore; if (ignore) { diff --git a/lib/loader/mixin/config.js b/lib/loader/mixin/config.js index 0d4c25b0..204938a9 100644 --- a/lib/loader/mixin/config.js +++ b/lib/loader/mixin/config.js @@ -1,7 +1,6 @@ 'use strict'; const debug = require('debug')('egg-core:config'); -const fs = require('fs'); const path = require('path'); const extend = require('extend2'); const assert = require('assert'); @@ -55,8 +54,8 @@ module.exports = { _preloadAppConfig() { const names = [ - 'config.default.js', - `config.${this.serverEnv}.js`, + 'config.default', + `config.${this.serverEnv}`, ]; const target = {}; for (const filename of names) { @@ -70,12 +69,13 @@ module.exports = { const isPlugin = type === 'plugin'; const isApp = type === 'app'; - let filepath = path.join(dirpath, 'config', filename); + let filepath = this.resolveModule(path.join(dirpath, 'config', filename)); // let config.js compatible - if (filename === 'config.default.js' && !fs.existsSync(filepath)) { - filepath = path.join(dirpath, 'config/config.js'); + if (filename === 'config.default' && !filepath) { + filepath = this.resolveModule(path.join(dirpath, 'config/config')); } const config = this.loadFile(filepath, this.appInfo, extraInject); + if (!config) return null; if (isPlugin || isApp) { diff --git a/lib/loader/mixin/custom.js b/lib/loader/mixin/custom.js index 4d3fb41c..adfd4f92 100644 --- a/lib/loader/mixin/custom.js +++ b/lib/loader/mixin/custom.js @@ -22,7 +22,7 @@ module.exports = { */ loadCustomApp() { this.getLoadUnits() - .forEach(unit => this.loadFile(path.join(unit.path, 'app.js'))); + .forEach(unit => this.loadFile(this.resolveModule(path.join(unit.path, 'app')))); }, /** @@ -30,7 +30,7 @@ module.exports = { */ loadCustomAgent() { this.getLoadUnits() - .forEach(unit => this.loadFile(path.join(unit.path, 'agent.js'))); + .forEach(unit => this.loadFile(this.resolveModule(path.join(unit.path, 'agent')))); }, }; diff --git a/lib/loader/mixin/extend.js b/lib/loader/mixin/extend.js index 45d527d0..fc24b391 100644 --- a/lib/loader/mixin/extend.js +++ b/lib/loader/mixin/extend.js @@ -3,7 +3,6 @@ const debug = require('debug')('egg-core:extend'); const deprecate = require('depd')('egg'); const path = require('path'); -const utils = require('../../utils'); const originalPrototypes = { request: require('koa/lib/request'), @@ -96,13 +95,13 @@ module.exports = { const isAddUnittest = 'EGG_MOCK_SERVER_ENV' in process.env && this.serverEnv !== 'unittest'; for (let i = 0, l = filepaths.length; i < l; i++) { const filepath = filepaths[i]; - filepaths.push(filepath + `.${this.serverEnv}.js`); - if (isAddUnittest) filepaths.push(filepath + '.unittest.js'); + filepaths.push(filepath + `.${this.serverEnv}`); + if (isAddUnittest) filepaths.push(filepath + '.unittest'); } const mergeRecord = new Map(); for (let filepath of filepaths) { - filepath = utils.resolveModule(filepath); + filepath = this.resolveModule(filepath); if (!filepath) { continue; } else if (filepath.endsWith('/index.js')) { @@ -110,7 +109,7 @@ module.exports = { deprecate(`app/extend/${name}/index.js is deprecated, use app/extend/${name}.js instead`); } - const ext = utils.loadFile(filepath); + const ext = this.loadFile(filepath); const properties = Object.getOwnPropertyNames(ext) .concat(Object.getOwnPropertySymbols(ext)); diff --git a/lib/loader/mixin/plugin.js b/lib/loader/mixin/plugin.js index 158355a8..ba563b68 100644 --- a/lib/loader/mixin/plugin.js +++ b/lib/loader/mixin/plugin.js @@ -56,11 +56,11 @@ module.exports = { */ loadPlugin() { // loader plugins from application - const appPlugins = this.readPluginConfigs(path.join(this.options.baseDir, 'config/plugin.default.js')); + const appPlugins = this.readPluginConfigs(path.join(this.options.baseDir, 'config/plugin.default')); debug('Loaded app plugins: %j', Object.keys(appPlugins)); // loader plugins from framework - const eggPluginConfigPaths = this.eggPaths.map(eggPath => path.join(eggPath, 'config/plugin.default.js')); + const eggPluginConfigPaths = this.eggPaths.map(eggPath => path.join(eggPath, 'config/plugin.default')); const eggPlugins = this.readPluginConfigs(eggPluginConfigPaths); debug('Loaded egg plugins: %j', Object.keys(eggPlugins)); @@ -159,20 +159,22 @@ module.exports = { } const plugins = {}; - for (let configPath of newConfigPaths) { + for (const configPath of newConfigPaths) { + let filepath = this.resolveModule(configPath); + // let plugin.js compatible - if (configPath.endsWith('plugin.default.js') && !fs.existsSync(configPath)) { - configPath = configPath.replace(/plugin\.default\.js$/, 'plugin.js'); + if (configPath.endsWith('plugin.default') && !filepath) { + filepath = this.resolveModule(configPath.replace(/plugin\.default$/, 'plugin')); } - if (!fs.existsSync(configPath)) { + if (!filepath) { continue; } - const config = loadFile(configPath); + const config = loadFile(filepath); for (const name in config) { - this.normalizePluginConfig(config, name, configPath); + this.normalizePluginConfig(config, name, filepath); } this._extendPlugins(plugins, config); diff --git a/lib/loader/mixin/router.js b/lib/loader/mixin/router.js index af202d2d..8a95a3b1 100644 --- a/lib/loader/mixin/router.js +++ b/lib/loader/mixin/router.js @@ -12,6 +12,6 @@ module.exports = { */ loadRouter() { // 加载 router.js - this.loadFile(path.join(this.options.baseDir, 'app/router.js')); + this.loadFile(this.resolveModule(path.join(this.options.baseDir, 'app/router'))); }, }; diff --git a/lib/utils/index.js b/lib/utils/index.js index 87caa7a4..d3266470 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -12,7 +12,7 @@ module.exports = { try { // if not js module, just return content buffer const extname = path.extname(filepath); - if (![ '.js', '.node', '.json', '' ].includes(extname)) { + if (extname && !require.extensions[extname]) { return fs.readFileSync(filepath); } // require js module @@ -27,14 +27,6 @@ module.exports = { } }, - resolveModule(filepath) { - try { - return require.resolve(filepath); - } catch (e) { - return undefined; - } - }, - methods: [ 'head', 'options', 'get', 'put', 'patch', 'post', 'delete' ], async callFn(fn, args, ctx) { diff --git a/test/egg-ts.test.js b/test/egg-ts.test.js new file mode 100644 index 00000000..699ca95d --- /dev/null +++ b/test/egg-ts.test.js @@ -0,0 +1,88 @@ +'use strict'; + +const request = require('supertest'); +const assert = require('assert'); +const utils = require('./utils'); + +describe('test/egg-ts.test.js', () => { + let app; + + before(() => { + require.extensions['.ts'] = require.extensions['.js']; + }); + + after(() => { + delete require.extensions['.ts']; + }); + + it('should support load ts file', async () => { + app = utils.createApp('egg-ts', { + typescript: true, + }); + + app.Helper = class Helper {}; + app.loader.loadPlugin(); + app.loader.loadConfig(); + app.loader.loadApplicationExtend(); + app.loader.loadAgentExtend(); + app.loader.loadRequestExtend(); + app.loader.loadResponseExtend(); + app.loader.loadContextExtend(); + app.loader.loadHelperExtend(); + app.loader.loadService(); + app.loader.loadController(); + app.loader.loadRouter(); + app.loader.loadPlugin(); + app.loader.loadMiddleware(); + app.loader.loadCustomApp(); + app.loader.loadCustomAgent(); + + await request(app.callback()) + .get('/') + .expect(res => { + assert(res.text.includes('from extend context')); + assert(res.text.includes('from extend application')); + assert(res.text.includes('from extend request')); + assert(res.text.includes('from extend agent')); + assert(res.text.includes('from extend helper')); + assert(res.text.includes('from extend response')); + assert(res.text.includes('from custom app')); + assert(res.text.includes('from custom agent')); + assert(res.text.includes('from plugins')); + assert(res.text.includes('from config.default')); + assert(res.text.includes('from middleware')); + assert(res.text.includes('from service')); + }) + .expect(200); + }); + + it('should not load d.ts files while typescript was true', async () => { + app = utils.createApp('egg-ts-js', { + typescript: true, + }); + + app.loader.loadController(); + assert(!app.controller.god); + assert(app.controller.test); + }); + + it('should support load ts,js files', async () => { + app = utils.createApp('egg-ts-js', { + typescript: true, + }); + + app.loader.loadService(); + assert(app.serviceClasses.lord); + assert(app.serviceClasses.test); + }); + + it('should not load ts files while typescript was false', async () => { + app = utils.createApp('egg-ts-js'); + + app.loader.loadApplicationExtend(); + app.loader.loadService(); + assert(!app.appExtend); + assert(app.serviceClasses.lord); + assert(!app.serviceClasses.test); + }); +}); diff --git a/test/fixtures/egg-ts-js/app/controller/god.d.ts b/test/fixtures/egg-ts-js/app/controller/god.d.ts new file mode 100644 index 00000000..e69de29b diff --git a/test/fixtures/egg-ts-js/app/controller/test.ts b/test/fixtures/egg-ts-js/app/controller/test.ts new file mode 100644 index 00000000..e868e3f7 --- /dev/null +++ b/test/fixtures/egg-ts-js/app/controller/test.ts @@ -0,0 +1,3 @@ +module.exports = async ctx => { + ctx.body = 'ok'; +} \ No newline at end of file diff --git a/test/fixtures/egg-ts-js/app/extend/application.ts b/test/fixtures/egg-ts-js/app/extend/application.ts new file mode 100644 index 00000000..a867bb33 --- /dev/null +++ b/test/fixtures/egg-ts-js/app/extend/application.ts @@ -0,0 +1,3 @@ +module.exports = { + appExtend: 'hello' +} \ No newline at end of file diff --git a/test/fixtures/egg-ts-js/app/service/lord.js b/test/fixtures/egg-ts-js/app/service/lord.js new file mode 100644 index 00000000..c9d1df43 --- /dev/null +++ b/test/fixtures/egg-ts-js/app/service/lord.js @@ -0,0 +1,5 @@ +module.exports = class LordService { + jsService() { + return 'from js service'; + } +} \ No newline at end of file diff --git a/test/fixtures/egg-ts-js/app/service/test.ts b/test/fixtures/egg-ts-js/app/service/test.ts new file mode 100644 index 00000000..96ac64eb --- /dev/null +++ b/test/fixtures/egg-ts-js/app/service/test.ts @@ -0,0 +1,5 @@ +module.exports = class TestService { + tsService() { + return 'from ts service'; + } +} \ No newline at end of file diff --git a/test/fixtures/egg-ts-js/package.json b/test/fixtures/egg-ts-js/package.json new file mode 100644 index 00000000..d71db5a8 --- /dev/null +++ b/test/fixtures/egg-ts-js/package.json @@ -0,0 +1,3 @@ +{ + "name": "egg-ts" +} diff --git a/test/fixtures/egg-ts/agent.ts b/test/fixtures/egg-ts/agent.ts new file mode 100644 index 00000000..b4dc7cbf --- /dev/null +++ b/test/fixtures/egg-ts/agent.ts @@ -0,0 +1,3 @@ +module.exports = app => { + app.fromCustomAgent = 'from custom agent'; +}; diff --git a/test/fixtures/egg-ts/app.ts b/test/fixtures/egg-ts/app.ts new file mode 100644 index 00000000..56b5238b --- /dev/null +++ b/test/fixtures/egg-ts/app.ts @@ -0,0 +1,3 @@ +module.exports = app => { + app.fromCustomApp = 'from custom app'; +}; diff --git a/test/fixtures/egg-ts/app/controller/home.ts b/test/fixtures/egg-ts/app/controller/home.ts new file mode 100644 index 00000000..353e856a --- /dev/null +++ b/test/fixtures/egg-ts/app/controller/home.ts @@ -0,0 +1,18 @@ +module.exports = async ctx => { + const serviceText = ctx.service.test.getTest(); + const helper = ctx.helper = new ctx.app.Helper(); + ctx.body = [ + ctx.contextShow(), + ctx.app.applicationShow(), + ctx.request.requestShow(), + ctx.response.responseShow(), + ctx.app.agentShow(), + ctx.helper.helperShow(), + ctx.app.fromCustomApp, + ctx.app.fromCustomAgent, + ctx.app.config.test, + ctx.app.config.testFromA, + ctx.mid, + serviceText + ].join(','); +} \ No newline at end of file diff --git a/test/fixtures/egg-ts/app/extend/agent.ts b/test/fixtures/egg-ts/app/extend/agent.ts new file mode 100644 index 00000000..48f7a077 --- /dev/null +++ b/test/fixtures/egg-ts/app/extend/agent.ts @@ -0,0 +1,5 @@ +module.exports = { + agentShow() { + return 'from extend agent'; + } +} \ No newline at end of file diff --git a/test/fixtures/egg-ts/app/extend/application.ts b/test/fixtures/egg-ts/app/extend/application.ts new file mode 100644 index 00000000..f08d3b3f --- /dev/null +++ b/test/fixtures/egg-ts/app/extend/application.ts @@ -0,0 +1,5 @@ +module.exports = { + applicationShow() { + return 'from extend application'; + } +} \ No newline at end of file diff --git a/test/fixtures/egg-ts/app/extend/context.ts b/test/fixtures/egg-ts/app/extend/context.ts new file mode 100644 index 00000000..99624e1e --- /dev/null +++ b/test/fixtures/egg-ts/app/extend/context.ts @@ -0,0 +1,5 @@ +module.exports = { + contextShow() { + return 'from extend context'; + } +} \ No newline at end of file diff --git a/test/fixtures/egg-ts/app/extend/helper.ts b/test/fixtures/egg-ts/app/extend/helper.ts new file mode 100644 index 00000000..1f7209d6 --- /dev/null +++ b/test/fixtures/egg-ts/app/extend/helper.ts @@ -0,0 +1,5 @@ +module.exports = { + helperShow() { + return 'from extend helper'; + } +} \ No newline at end of file diff --git a/test/fixtures/egg-ts/app/extend/request.ts b/test/fixtures/egg-ts/app/extend/request.ts new file mode 100644 index 00000000..5672f9bc --- /dev/null +++ b/test/fixtures/egg-ts/app/extend/request.ts @@ -0,0 +1,5 @@ +module.exports = { + requestShow() { + return 'from extend request'; + } +} \ No newline at end of file diff --git a/test/fixtures/egg-ts/app/extend/response.ts b/test/fixtures/egg-ts/app/extend/response.ts new file mode 100644 index 00000000..21a270d8 --- /dev/null +++ b/test/fixtures/egg-ts/app/extend/response.ts @@ -0,0 +1,5 @@ +module.exports = { + responseShow() { + return 'from extend response'; + } +} \ No newline at end of file diff --git a/test/fixtures/egg-ts/app/middleware/mid.ts b/test/fixtures/egg-ts/app/middleware/mid.ts new file mode 100644 index 00000000..386cbc8c --- /dev/null +++ b/test/fixtures/egg-ts/app/middleware/mid.ts @@ -0,0 +1,6 @@ +module.exports = () => { + return async (ctx, next) => { + ctx.mid = 'from middleware'; + await next(); + } +} \ No newline at end of file diff --git a/test/fixtures/egg-ts/app/router.ts b/test/fixtures/egg-ts/app/router.ts new file mode 100644 index 00000000..366095d1 --- /dev/null +++ b/test/fixtures/egg-ts/app/router.ts @@ -0,0 +1,4 @@ +module.exports = app => { + const { router, controller } = app; + router.get('/', controller.home); +} \ No newline at end of file diff --git a/test/fixtures/egg-ts/app/service/Test.ts b/test/fixtures/egg-ts/app/service/Test.ts new file mode 100644 index 00000000..8da345f7 --- /dev/null +++ b/test/fixtures/egg-ts/app/service/Test.ts @@ -0,0 +1,5 @@ +module.exports = class TestService { + getTest() { + return 'from service'; + } +} \ No newline at end of file diff --git a/test/fixtures/egg-ts/config/config.default.ts b/test/fixtures/egg-ts/config/config.default.ts new file mode 100644 index 00000000..bc4c4552 --- /dev/null +++ b/test/fixtures/egg-ts/config/config.default.ts @@ -0,0 +1,6 @@ +module.exports = () => { + return { + middleware: [ 'mid' ], + test: 'from config.default', + }; +} \ No newline at end of file diff --git a/test/fixtures/egg-ts/config/plugin.ts b/test/fixtures/egg-ts/config/plugin.ts new file mode 100644 index 00000000..917b0963 --- /dev/null +++ b/test/fixtures/egg-ts/config/plugin.ts @@ -0,0 +1,7 @@ +const path = require('path'); + +module.exports = { + a: { + path: path.resolve(__dirname, '../plugins/a'), + } +} \ No newline at end of file diff --git a/test/fixtures/egg-ts/package.json b/test/fixtures/egg-ts/package.json new file mode 100644 index 00000000..d71db5a8 --- /dev/null +++ b/test/fixtures/egg-ts/package.json @@ -0,0 +1,3 @@ +{ + "name": "egg-ts" +} diff --git a/test/fixtures/egg-ts/plugins/a/config/config.default.ts b/test/fixtures/egg-ts/plugins/a/config/config.default.ts new file mode 100644 index 00000000..6878f7f3 --- /dev/null +++ b/test/fixtures/egg-ts/plugins/a/config/config.default.ts @@ -0,0 +1,5 @@ +module.exports = () => { + return { + testFromA: 'from plugins', + }; +} diff --git a/test/fixtures/egg-ts/plugins/a/package.json b/test/fixtures/egg-ts/plugins/a/package.json new file mode 100644 index 00000000..1aeaf2c8 --- /dev/null +++ b/test/fixtures/egg-ts/plugins/a/package.json @@ -0,0 +1,3 @@ +{ + "name": "a" +} \ No newline at end of file diff --git a/test/loader/file_loader.test.js b/test/loader/file_loader.test.js index 3da37eec..d6fa9c41 100644 --- a/test/loader/file_loader.test.js +++ b/test/loader/file_loader.test.js @@ -254,6 +254,17 @@ describe('test/loader/file_loader.test.js', () => { }, /_private is not match 'a-z0-9_-' in _private.js/); }); + it('should throw when typescript was true but no ts extension', () => { + const mod = {}; + assert.throws(() => { + new FileLoader({ + directory: path.join(dirBase, 'error/dotdir'), + target: mod, + typescript: true, + }).load(); + }, /`require.extensions` should contains `.ts` while `options.typescript` was true/); + }); + describe('caseStyle', () => { it('should load when caseStyle = upper', () => { const target = {};