A dictionary of file extensions and associated module loaders for automatic transpiler registration.
npx @tessl/cli install tessl/npm-interpret@3.1.0Interpret is a comprehensive dictionary of file extensions and their associated module loaders, enabling automatic registration of transpilers and compilers for various JavaScript variants and other file types. It provides mapping from file extensions to the appropriate Node.js require.extensions loaders for seamless transpilation support.
npm install interpretconst { extensions, jsVariants } = require('interpret');For ESM (requires transpilation):
import { extensions, jsVariants } from 'interpret';const interpret = require('interpret');
// Check if a file extension has a loader
const tsLoader = interpret.extensions['.ts'];
console.log(tsLoader); // Array of loader options for TypeScript
// Get only JavaScript variant extensions
const jsOnlyLoaders = interpret.jsVariants;
console.log(jsOnlyLoaders['.jsx']); // Loader options for JSX files
// Implementation pattern for using loaders
function registerLoader(extension) {
const loader = interpret.extensions[extension];
if (!loader) {
console.log('No loader for', extension);
return;
}
if (loader === null) {
// Use default Node.js loader
return;
}
if (typeof loader === 'string') {
// Simple module name
require(loader);
} else if (Array.isArray(loader)) {
// Try each loader until one works
for (const option of loader) {
try {
if (typeof option === 'string') {
require(option);
break;
} else if (option.module) {
const hook = require(option.module);
if (option.register) {
option.register(hook);
}
break;
}
} catch (err) {
// Try next option
}
}
} else if (loader.module) {
// Object with module and register function
const hook = require(loader.module);
if (loader.register) {
loader.register(hook);
}
}
}Complete mapping of file extensions to their associated module loaders.
/**
* Dictionary mapping file extensions to loader configurations
* @type {Object<string, LoaderConfig>}
*/
const extensions: {
[extension: string]: LoaderConfig;
};
/**
* Loader configuration can be:
* - null: Use default Node.js loader
* - string: Module name to require
* - LoaderObject: Module with custom registration
* - LoaderConfig[]: Array of fallback options
*/
type LoaderConfig = null | string | LoaderObject | LoaderConfig[];
/**
* Loader object with module and custom registration function
*/
interface LoaderObject {
/** Module name to require */
module: string;
/** Custom registration function */
register: (hook: any, config?: any) => void;
}Subset of extensions containing only JavaScript-related file types.
/**
* Dictionary of JavaScript variant extensions and their loaders
* Same structure as extensions but filtered to JS-related types only
* @type {Object<string, LoaderConfig>}
*/
const jsVariants: {
[extension: string]: LoaderConfig;
};Extensions included in the jsVariants object for JavaScript and JavaScript-like languages:
// Native Node.js loaders
'.js': null,
'.cjs': 'interpret/cjs-stub',
'.mjs': 'interpret/mjs-stub',
// JSX support
'.jsx': [
{
module: '@babel/register',
register: (hook, config) => void
},
'sucrase/register/jsx'
],
// TypeScript support
'.ts': [
'ts-node/register',
'sucrase/register/ts',
{
module: '@babel/register',
register: (hook, config) => void
},
{
module: 'esbuild-register/dist/node',
register: (mod, config) => void
},
{
module: '@swc/register',
register: (hook, config) => void
}
],
'.tsx': [
'ts-node/register',
'sucrase/register/tsx',
{
module: '@babel/register',
register: (hook, config) => void
},
{
module: 'esbuild-register/dist/node',
register: (mod, config) => void
},
{
module: '@swc/register',
register: (hook, config) => void
}
],
// CoffeeScript support
'.coffee': 'coffeescript/register',
'.coffee.md': 'coffeescript/register',
'.litcoffee': 'coffeescript/register',
// ESM support
'.esm.js': {
module: 'esm',
register: (hook) => void
},
// MDX support
'.mdx': '@mdx-js/register'Extensions that target specific transpilers:
// Babel-specific extensions
'.babel.js': {
module: '@babel/register',
register: (hook, config) => void
},
'.babel.jsx': {
module: '@babel/register',
register: (hook, config) => void
},
'.babel.ts': [{
module: '@babel/register',
register: (hook, config) => void
}],
'.babel.tsx': {
module: '@babel/register',
register: (hook, config) => void
},
// ESBuild-specific extensions
'.esbuild.js': {
module: 'esbuild-register/dist/node',
register: (mod, config) => void
},
'.esbuild.jsx': {
module: 'esbuild-register/dist/node',
register: (mod, config) => void
},
'.esbuild.ts': {
module: 'esbuild-register/dist/node',
register: (mod, config) => void
},
'.esbuild.tsx': {
module: 'esbuild-register/dist/node',
register: (mod, config) => void
},
// Sucrase-specific extensions
'.sucrase.js': {
module: 'sucrase/dist/register',
register: (hook, config) => void
},
'.sucrase.jsx': {
module: 'sucrase/dist/register',
register: (hook, config) => void
},
'.sucrase.ts': {
module: 'sucrase/dist/register',
register: (hook, config) => void
},
'.sucrase.tsx': {
module: 'sucrase/dist/register',
register: (hook, config) => void
},
// SWC-specific extensions
'.swc.js': {
module: '@swc/register',
register: (hook, config) => void
},
'.swc.jsx': {
module: '@swc/register',
register: (hook, config) => void
},
'.swc.ts': {
module: '@swc/register',
register: (hook, config) => void
},
'.swc.tsx': {
module: '@swc/register',
register: (hook, config) => void
}Extensions available in the main extensions object but not included in jsVariants:
// Native Node.js loaders
'.json': null,
'.node': null,
// TypeScript CommonJS modules
'.cts': ['ts-node/register'],
// Data formats
'.json5': 'json5/lib/register',
'.yaml': 'yaml-hook/register',
'.yml': 'yaml-hook/register',
'.toml': {
module: 'toml-require',
register: (hook, config) => void
}The package includes internal helper functions used within loader configurations:
/**
* Helper functions for matching specific file extensions
* These are used internally by the loader configurations
*/
function endsInJsx(filename: string): boolean;
function endsInTs(filename: string): boolean;
function endsInTsx(filename: string): boolean;
function endsInBabelJs(filename: string): boolean;
function endsInBabelJsx(filename: string): boolean;
function endsInBabelTs(filename: string): boolean;
function endsInBabelTsx(filename: string): boolean;
function endsInEsbuildJs(filename: string): boolean;
function endsInEsbuildJsx(filename: string): boolean;
function endsInEsbuildTs(filename: string): boolean;
function endsInEsbuildTsx(filename: string): boolean;
function endsInSucraseJs(filename: string): boolean;
function endsInSucraseJsx(filename: string): boolean;
function endsInSucraseTs(filename: string): boolean;
function endsInSucraseTsx(filename: string): boolean;
function endsInSwcJs(filename: string): boolean;
function endsInSwcJsx(filename: string): boolean;
function endsInSwcTs(filename: string): boolean;
function endsInSwcTsx(filename: string): boolean;
/**
* Helper function to check if a file is in node_modules
* Used for ignoring node_modules in some transpiler configurations
*/
function isNodeModules(file: string): boolean;The package includes stub files for CommonJS and ES Modules:
/**
* Path to CommonJS stub file that registers .cjs extension
* Resolves to: path.join(__dirname, 'cjs-stub')
* Contents: require.extensions['.cjs'] = null;
*/
const cjsStub: string;
/**
* Path to ES Module stub file that registers .mjs extension
* Resolves to: path.join(__dirname, 'mjs-stub')
* Contents: require.extensions['.mjs'] = null;
*/
const mjsStub: string;const interpret = require('interpret');
function hasLoader(extension) {
return extension in interpret.extensions;
}
function isJavaScriptVariant(extension) {
return extension in interpret.jsVariants;
}const interpret = require('interpret');
function attemptRequire(extension, filepath) {
const loader = interpret.extensions[extension];
if (!loader) {
throw new Error(`No loader available for ${extension}`);
}
if (loader === null) {
// Use default Node.js loader
return require(filepath);
}
// Register the appropriate loader
registerLoader(loader);
// Now require the file
return require(filepath);
}
function registerLoader(loader) {
if (typeof loader === 'string') {
require(loader);
} else if (Array.isArray(loader)) {
// Try each loader until one succeeds
for (const option of loader) {
try {
registerSingleLoader(option);
return;
} catch (err) {
// Continue to next option
}
}
throw new Error('No working loader found');
} else if (loader && loader.module) {
registerSingleLoader(loader);
}
}
function registerSingleLoader(loader) {
if (typeof loader === 'string') {
require(loader);
} else if (loader.module) {
const hook = require(loader.module);
if (loader.register) {
loader.register(hook);
}
}
}Most loaders accept configuration through the register function's second parameter:
// Babel configuration example
const babelLoader = {
module: '@babel/register',
register: (hook, config) => {
const defaultConfig = {
rootMode: 'upward-optional',
overrides: [{
only: [filename => filename.endsWith('.tsx')],
presets: [
'@babel/preset-env',
'@babel/preset-react',
['@babel/preset-typescript', { isTSX: true, allExtensions: true }]
]
}]
};
hook(Object.assign({}, defaultConfig, config, { extensions: '.tsx' }));
}
};
// ESBuild configuration example
const esbuildLoader = {
module: 'esbuild-register/dist/node',
register: (mod, config) => {
const defaultConfig = {
target: 'node' + process.version.slice(1),
hookMatcher: filename => filename.endsWith('.ts')
};
mod.register(Object.assign({}, defaultConfig, config, { extensions: ['.ts'] }));
}
};
// SWC configuration example
const swcLoader = {
module: '@swc/register',
register: (hook, config) => {
const defaultConfig = {
only: [filename => filename.endsWith('.ts')],
ignore: [filepath => filepath.includes('node_modules')],
jsc: {
parser: { syntax: 'typescript' }
},
module: { type: 'commonjs' }
};
hook(Object.assign({}, defaultConfig, config, { extensions: '.ts' }));
}
};The package itself does not throw errors - it provides configuration data. However, when implementing loader registration, common error scenarios include:
function safeRegisterLoader(extension, filepath) {
try {
return attemptRequire(extension, filepath);
} catch (err) {
if (err.code === 'MODULE_NOT_FOUND') {
console.warn(`Loader for ${extension} not installed:`, err.message);
// Optionally fall back to default loader
return require(filepath);
}
throw err;
}
}