Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 38 additions & 20 deletions src/require.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const { extname } = require('path');
const { readFileSync } = require('fs');
const tsm = require('./utils');

import type { Config } from 'tsm/config';
import type { Config, Options } from 'tsm/config';
type TSM = typeof import('./utils.d');

type Module = NodeJS.Module & {
Expand All @@ -16,11 +17,11 @@ let uconf = env.file && require(env.file);
let config: Config = (tsm as TSM).$finalize(env, uconf);

declare const $$req: NodeJS.Require;
const tsrequire = 'var $$req=require;require=(' + function () {
const tsrequire = 'var $$req=require("module").createRequire(__filename);require=(' + function () {
let { existsSync } = $$req('fs');
let { URL, pathToFileURL } = $$req('url');

return new Proxy($$req, {
return new Proxy(require, {
// NOTE: only here if source is TS
apply(req, ctx, args: [id: string]) {
let [ident] = args;
Expand All @@ -47,29 +48,46 @@ const tsrequire = 'var $$req=require;require=(' + function () {
return existsSync(file) ? $$req(file) : $$req(ident);
}
})
} + ')();'
} + ')();';

function transform(source: string, options: Options): string {
esbuild = esbuild || require('esbuild');
return esbuild.transformSync(source, options).code;
}

function loader(Module: Module, sourcefile: string) {
let extn = extname(sourcefile);
let options = config[extn] || {};
let pitch = Module._compile!.bind(Module);

Module._compile = source => {
let options = config[extn];
if (options == null) return pitch(source, sourcefile);

let banner = options.banner || '';
if (/\.[mc]?tsx?$/.test(extn)) {
banner = tsrequire + banner;
}

esbuild = esbuild || require('esbuild');
let result = esbuild.transformSync(source, { ...options, banner, sourcefile });
return pitch(result.code, sourcefile);
};

return loadJS(Module, sourcefile);
options.sourcefile = sourcefile;

if (/\.[mc]?tsx?$/.test(extn)) {
options.banner = tsrequire + (options.banner || '');
}

if (config[extn] != null) {
Module._compile = source => {
let result = transform(source, options);
return pitch(result, sourcefile);
};
}

try {
return loadJS(Module, sourcefile);
} catch (err) {
let ec = err && (err as any).code;
if (ec !== 'ERR_REQUIRE_ESM') throw err;

let input = readFileSync(sourcefile, 'utf8');
let result = transform(input, { ...options, format: 'cjs' });
return pitch(result, sourcefile);
}
}

for (let extn in config) {
require.extensions[extn] = loader;
}

if (config['.js'] == null) {
require.extensions['.js'] = loader;
}
9 changes: 9 additions & 0 deletions test/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import * as js from '../fixtures/math.js';
import * as mjs from '../fixtures/utils.mjs';
// @ts-ignore - cannot find types
import * as cjs from '../fixtures/utils.cjs';
// @ts-ignore - cannot find types
import * as esm from '../fixtures/module/index.js';

// NOTE: avoid need for syntheticDefault + analysis
import * as data from '../fixtures/data.json';
Expand All @@ -31,4 +33,11 @@ assert.equal(typeof cjs, 'object', 'CJS :: typeof');
assert.equal(typeof cjs.dashify, 'function', 'CJS :: typeof :: dashify');
assert.equal(cjs.dashify('FooBar'), 'foo-bar', 'CJS :: value :: dashify');

// Checking ".js" with ESM content (type: module)
assert.equal(typeof esm, 'object', 'ESM.js :: typeof');
// @ts-ignore
assert.equal(typeof esm.hello, 'function', 'ESM.js :: typeof :: hello');
// @ts-ignore
assert.equal(esm.hello('you'), 'hello, you', 'ESM.js :: value :: hello');

console.log('DONE~!');
6 changes: 6 additions & 0 deletions test/fixtures/module/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @param {string} name
*/
export function hello(name) {
return `hello, ${name}`;
}
6 changes: 6 additions & 0 deletions test/fixtures/module/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @param {string} name
*/
export function hello(name) {
return `hello, ${name}`;
}
3 changes: 3 additions & 0 deletions test/fixtures/module/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "module"
}
14 changes: 14 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ const ts = require('./fixtures/math.ts');
const mts = require('./fixtures/utils.mts');
// @ts-ignore – prefers extensionless
const cts = require('./fixtures/utils.cts');
// @ts-ignore – prefers extensionless
const esm1 = require('./fixtures/module/index.js');
// @ts-ignore – prefers extensionless
const esm2 = require('./fixtures/module/index.mjs');

const props = {
foo: 'bar'
Expand Down Expand Up @@ -55,4 +59,14 @@ assert.equal(typeof cts, 'object', 'CTS :: typeof');
assert.equal(typeof cts.dashify, 'function', 'CTS :: typeof :: dashify');
assert.equal(cts.dashify('FooBar'), 'foo-bar', 'CTS :: value :: dashify');

assert(esm1, 'ESM.js :: typeof');
assert.equal(typeof esm1, 'object', 'ESM.js :: typeof');
assert.equal(typeof esm1.hello, 'function', 'ESM.js :: typeof :: hello');
assert.equal(esm1.hello('you'), 'hello, you', 'ESM.js :: value :: hello');

assert(esm2, 'ESM.mjs :: typeof');
assert.equal(typeof esm2, 'object', 'ESM.mjs :: typeof');
assert.equal(typeof esm2.hello, 'function', 'ESM.mjs :: typeof :: hello');
assert.equal(esm2.hello('you'), 'hello, you', 'ESM.mjs :: value :: hello');

console.log('DONE~!');
12 changes: 12 additions & 0 deletions test/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import * as cts from './fixtures/utils.cts';
import * as ts from './fixtures/math.ts';
// @ts-ignore – prefers extensionless
import tsx from './fixtures/App2.tsx';
// @ts-ignore – prefers extensionless
import * as esm1 from './fixtures/module/index.js';
// @ts-ignore – prefers extensionless
import * as esm2 from './fixtures/module/index.mjs';

const props = {
foo: 'bar'
Expand Down Expand Up @@ -53,4 +57,12 @@ assert.equal(typeof cts, 'object', 'CTS :: typeof');
assert.equal(typeof cts.dashify, 'function', 'CTS :: typeof :: dashify');
assert.equal(cts.dashify('FooBar'), 'foo-bar', 'CTS :: value :: dashify');

assert.equal(typeof esm1, 'object', 'ESM.js :: typeof');
assert.equal(typeof esm1.hello, 'function', 'ESM.js :: typeof :: hello');
assert.equal(esm1.hello('you'), 'hello, you', 'ESM.js :: value :: hello');

assert.equal(typeof esm2, 'object', 'ESM.mjs :: typeof');
assert.equal(typeof esm2.hello, 'function', 'ESM.mjs :: typeof :: hello');
assert.equal(esm2.hello('you'), 'hello, you', 'ESM.mjs :: value :: hello');

console.log('DONE~!');