0
# Interpret
1
2
Interpret 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.
3
4
## Package Information
5
6
- **Package Name**: interpret
7
- **Package Type**: npm
8
- **Language**: JavaScript
9
- **Installation**: `npm install interpret`
10
11
## Core Imports
12
13
```javascript
14
const { extensions, jsVariants } = require('interpret');
15
```
16
17
For ESM (requires transpilation):
18
19
```javascript
20
import { extensions, jsVariants } from 'interpret';
21
```
22
23
## Basic Usage
24
25
```javascript
26
const interpret = require('interpret');
27
28
// Check if a file extension has a loader
29
const tsLoader = interpret.extensions['.ts'];
30
console.log(tsLoader); // Array of loader options for TypeScript
31
32
// Get only JavaScript variant extensions
33
const jsOnlyLoaders = interpret.jsVariants;
34
console.log(jsOnlyLoaders['.jsx']); // Loader options for JSX files
35
36
// Implementation pattern for using loaders
37
function registerLoader(extension) {
38
const loader = interpret.extensions[extension];
39
40
if (!loader) {
41
console.log('No loader for', extension);
42
return;
43
}
44
45
if (loader === null) {
46
// Use default Node.js loader
47
return;
48
}
49
50
if (typeof loader === 'string') {
51
// Simple module name
52
require(loader);
53
} else if (Array.isArray(loader)) {
54
// Try each loader until one works
55
for (const option of loader) {
56
try {
57
if (typeof option === 'string') {
58
require(option);
59
break;
60
} else if (option.module) {
61
const hook = require(option.module);
62
if (option.register) {
63
option.register(hook);
64
}
65
break;
66
}
67
} catch (err) {
68
// Try next option
69
}
70
}
71
} else if (loader.module) {
72
// Object with module and register function
73
const hook = require(loader.module);
74
if (loader.register) {
75
loader.register(hook);
76
}
77
}
78
}
79
```
80
81
## Capabilities
82
83
### Extensions Dictionary
84
85
Complete mapping of file extensions to their associated module loaders.
86
87
```javascript { .api }
88
/**
89
* Dictionary mapping file extensions to loader configurations
90
* @type {Object<string, LoaderConfig>}
91
*/
92
const extensions: {
93
[extension: string]: LoaderConfig;
94
};
95
96
/**
97
* Loader configuration can be:
98
* - null: Use default Node.js loader
99
* - string: Module name to require
100
* - LoaderObject: Module with custom registration
101
* - LoaderConfig[]: Array of fallback options
102
*/
103
type LoaderConfig = null | string | LoaderObject | LoaderConfig[];
104
105
/**
106
* Loader object with module and custom registration function
107
*/
108
interface LoaderObject {
109
/** Module name to require */
110
module: string;
111
/** Custom registration function */
112
register: (hook: any, config?: any) => void;
113
}
114
```
115
116
### JavaScript Variants Dictionary
117
118
Subset of extensions containing only JavaScript-related file types.
119
120
```javascript { .api }
121
/**
122
* Dictionary of JavaScript variant extensions and their loaders
123
* Same structure as extensions but filtered to JS-related types only
124
* @type {Object<string, LoaderConfig>}
125
*/
126
const jsVariants: {
127
[extension: string]: LoaderConfig;
128
};
129
```
130
131
## Supported Extensions
132
133
### JavaScript Variants (jsVariants)
134
135
Extensions included in the jsVariants object for JavaScript and JavaScript-like languages:
136
137
```javascript { .api }
138
// Native Node.js loaders
139
'.js': null,
140
'.cjs': 'interpret/cjs-stub',
141
'.mjs': 'interpret/mjs-stub',
142
143
// JSX support
144
'.jsx': [
145
{
146
module: '@babel/register',
147
register: (hook, config) => void
148
},
149
'sucrase/register/jsx'
150
],
151
152
// TypeScript support
153
'.ts': [
154
'ts-node/register',
155
'sucrase/register/ts',
156
{
157
module: '@babel/register',
158
register: (hook, config) => void
159
},
160
{
161
module: 'esbuild-register/dist/node',
162
register: (mod, config) => void
163
},
164
{
165
module: '@swc/register',
166
register: (hook, config) => void
167
}
168
],
169
170
'.tsx': [
171
'ts-node/register',
172
'sucrase/register/tsx',
173
{
174
module: '@babel/register',
175
register: (hook, config) => void
176
},
177
{
178
module: 'esbuild-register/dist/node',
179
register: (mod, config) => void
180
},
181
{
182
module: '@swc/register',
183
register: (hook, config) => void
184
}
185
],
186
187
// CoffeeScript support
188
'.coffee': 'coffeescript/register',
189
'.coffee.md': 'coffeescript/register',
190
'.litcoffee': 'coffeescript/register',
191
192
// ESM support
193
'.esm.js': {
194
module: 'esm',
195
register: (hook) => void
196
},
197
198
// MDX support
199
'.mdx': '@mdx-js/register'
200
```
201
202
### Transpiler-Specific Extensions
203
204
Extensions that target specific transpilers:
205
206
```javascript { .api }
207
// Babel-specific extensions
208
'.babel.js': {
209
module: '@babel/register',
210
register: (hook, config) => void
211
},
212
'.babel.jsx': {
213
module: '@babel/register',
214
register: (hook, config) => void
215
},
216
'.babel.ts': [{
217
module: '@babel/register',
218
register: (hook, config) => void
219
}],
220
'.babel.tsx': {
221
module: '@babel/register',
222
register: (hook, config) => void
223
},
224
225
// ESBuild-specific extensions
226
'.esbuild.js': {
227
module: 'esbuild-register/dist/node',
228
register: (mod, config) => void
229
},
230
'.esbuild.jsx': {
231
module: 'esbuild-register/dist/node',
232
register: (mod, config) => void
233
},
234
'.esbuild.ts': {
235
module: 'esbuild-register/dist/node',
236
register: (mod, config) => void
237
},
238
'.esbuild.tsx': {
239
module: 'esbuild-register/dist/node',
240
register: (mod, config) => void
241
},
242
243
// Sucrase-specific extensions
244
'.sucrase.js': {
245
module: 'sucrase/dist/register',
246
register: (hook, config) => void
247
},
248
'.sucrase.jsx': {
249
module: 'sucrase/dist/register',
250
register: (hook, config) => void
251
},
252
'.sucrase.ts': {
253
module: 'sucrase/dist/register',
254
register: (hook, config) => void
255
},
256
'.sucrase.tsx': {
257
module: 'sucrase/dist/register',
258
register: (hook, config) => void
259
},
260
261
// SWC-specific extensions
262
'.swc.js': {
263
module: '@swc/register',
264
register: (hook, config) => void
265
},
266
'.swc.jsx': {
267
module: '@swc/register',
268
register: (hook, config) => void
269
},
270
'.swc.ts': {
271
module: '@swc/register',
272
register: (hook, config) => void
273
},
274
'.swc.tsx': {
275
module: '@swc/register',
276
register: (hook, config) => void
277
}
278
```
279
280
### Extensions Only (not in jsVariants)
281
282
Extensions available in the main extensions object but not included in jsVariants:
283
284
```javascript { .api }
285
// Native Node.js loaders
286
'.json': null,
287
'.node': null,
288
289
// TypeScript CommonJS modules
290
'.cts': ['ts-node/register'],
291
292
// Data formats
293
'.json5': 'json5/lib/register',
294
'.yaml': 'yaml-hook/register',
295
'.yml': 'yaml-hook/register',
296
'.toml': {
297
module: 'toml-require',
298
register: (hook, config) => void
299
}
300
```
301
302
### Internal Helper Functions
303
304
The package includes internal helper functions used within loader configurations:
305
306
```javascript { .api }
307
/**
308
* Helper functions for matching specific file extensions
309
* These are used internally by the loader configurations
310
*/
311
function endsInJsx(filename: string): boolean;
312
function endsInTs(filename: string): boolean;
313
function endsInTsx(filename: string): boolean;
314
function endsInBabelJs(filename: string): boolean;
315
function endsInBabelJsx(filename: string): boolean;
316
function endsInBabelTs(filename: string): boolean;
317
function endsInBabelTsx(filename: string): boolean;
318
function endsInEsbuildJs(filename: string): boolean;
319
function endsInEsbuildJsx(filename: string): boolean;
320
function endsInEsbuildTs(filename: string): boolean;
321
function endsInEsbuildTsx(filename: string): boolean;
322
function endsInSucraseJs(filename: string): boolean;
323
function endsInSucraseJsx(filename: string): boolean;
324
function endsInSucraseTs(filename: string): boolean;
325
function endsInSucraseTsx(filename: string): boolean;
326
function endsInSwcJs(filename: string): boolean;
327
function endsInSwcJsx(filename: string): boolean;
328
function endsInSwcTs(filename: string): boolean;
329
function endsInSwcTsx(filename: string): boolean;
330
331
/**
332
* Helper function to check if a file is in node_modules
333
* Used for ignoring node_modules in some transpiler configurations
334
*/
335
function isNodeModules(file: string): boolean;
336
```
337
338
### Stub Files
339
340
The package includes stub files for CommonJS and ES Modules:
341
342
```javascript { .api }
343
/**
344
* Path to CommonJS stub file that registers .cjs extension
345
* Resolves to: path.join(__dirname, 'cjs-stub')
346
* Contents: require.extensions['.cjs'] = null;
347
*/
348
const cjsStub: string;
349
350
/**
351
* Path to ES Module stub file that registers .mjs extension
352
* Resolves to: path.join(__dirname, 'mjs-stub')
353
* Contents: require.extensions['.mjs'] = null;
354
*/
355
const mjsStub: string;
356
```
357
358
## Usage Patterns
359
360
### Basic Extension Check
361
362
```javascript
363
const interpret = require('interpret');
364
365
function hasLoader(extension) {
366
return extension in interpret.extensions;
367
}
368
369
function isJavaScriptVariant(extension) {
370
return extension in interpret.jsVariants;
371
}
372
```
373
374
### Loader Registration Implementation
375
376
```javascript
377
const interpret = require('interpret');
378
379
function attemptRequire(extension, filepath) {
380
const loader = interpret.extensions[extension];
381
382
if (!loader) {
383
throw new Error(`No loader available for ${extension}`);
384
}
385
386
if (loader === null) {
387
// Use default Node.js loader
388
return require(filepath);
389
}
390
391
// Register the appropriate loader
392
registerLoader(loader);
393
394
// Now require the file
395
return require(filepath);
396
}
397
398
function registerLoader(loader) {
399
if (typeof loader === 'string') {
400
require(loader);
401
} else if (Array.isArray(loader)) {
402
// Try each loader until one succeeds
403
for (const option of loader) {
404
try {
405
registerSingleLoader(option);
406
return;
407
} catch (err) {
408
// Continue to next option
409
}
410
}
411
throw new Error('No working loader found');
412
} else if (loader && loader.module) {
413
registerSingleLoader(loader);
414
}
415
}
416
417
function registerSingleLoader(loader) {
418
if (typeof loader === 'string') {
419
require(loader);
420
} else if (loader.module) {
421
const hook = require(loader.module);
422
if (loader.register) {
423
loader.register(hook);
424
}
425
}
426
}
427
```
428
429
### Configuration Examples
430
431
Most loaders accept configuration through the register function's second parameter:
432
433
```javascript
434
// Babel configuration example
435
const babelLoader = {
436
module: '@babel/register',
437
register: (hook, config) => {
438
const defaultConfig = {
439
rootMode: 'upward-optional',
440
overrides: [{
441
only: [filename => filename.endsWith('.tsx')],
442
presets: [
443
'@babel/preset-env',
444
'@babel/preset-react',
445
['@babel/preset-typescript', { isTSX: true, allExtensions: true }]
446
]
447
}]
448
};
449
450
hook(Object.assign({}, defaultConfig, config, { extensions: '.tsx' }));
451
}
452
};
453
454
// ESBuild configuration example
455
const esbuildLoader = {
456
module: 'esbuild-register/dist/node',
457
register: (mod, config) => {
458
const defaultConfig = {
459
target: 'node' + process.version.slice(1),
460
hookMatcher: filename => filename.endsWith('.ts')
461
};
462
463
mod.register(Object.assign({}, defaultConfig, config, { extensions: ['.ts'] }));
464
}
465
};
466
467
// SWC configuration example
468
const swcLoader = {
469
module: '@swc/register',
470
register: (hook, config) => {
471
const defaultConfig = {
472
only: [filename => filename.endsWith('.ts')],
473
ignore: [filepath => filepath.includes('node_modules')],
474
jsc: {
475
parser: { syntax: 'typescript' }
476
},
477
module: { type: 'commonjs' }
478
};
479
480
hook(Object.assign({}, defaultConfig, config, { extensions: '.ts' }));
481
}
482
};
483
```
484
485
## Error Handling
486
487
The package itself does not throw errors - it provides configuration data. However, when implementing loader registration, common error scenarios include:
488
489
- **Missing dependencies**: Loader modules not installed
490
- **Configuration errors**: Invalid configuration passed to register functions
491
- **Loader conflicts**: Multiple loaders registering for the same extension
492
- **Syntax errors**: Files that don't match the expected syntax for their extension
493
494
```javascript
495
function safeRegisterLoader(extension, filepath) {
496
try {
497
return attemptRequire(extension, filepath);
498
} catch (err) {
499
if (err.code === 'MODULE_NOT_FOUND') {
500
console.warn(`Loader for ${extension} not installed:`, err.message);
501
// Optionally fall back to default loader
502
return require(filepath);
503
}
504
throw err;
505
}
506
}
507
```