1'use strict';
2
3const {
4  RegExpPrototypeExec,
5  Uint8Array,
6} = primordials;
7const { getOptionValue } = require('internal/options');
8
9const { closeSync, openSync, readSync } = require('fs');
10
11const experimentalWasmModules = getOptionValue('--experimental-wasm-modules');
12
13const extensionFormatMap = {
14  '__proto__': null,
15  '.cjs': 'commonjs',
16  '.js': 'module',
17  '.json': 'json',
18  '.mjs': 'module',
19};
20
21const legacyExtensionFormatMap = {
22  '__proto__': null,
23  '.cjs': 'commonjs',
24  '.js': 'commonjs',
25  '.json': 'commonjs',
26  '.mjs': 'module',
27  '.node': 'commonjs',
28};
29
30if (experimentalWasmModules) {
31  extensionFormatMap['.wasm'] = legacyExtensionFormatMap['.wasm'] = 'wasm';
32}
33
34/**
35 * @param {string} mime
36 * @returns {string | null}
37 */
38function mimeToFormat(mime) {
39  if (
40    RegExpPrototypeExec(
41      /^\s*(text|application)\/javascript\s*(;\s*charset=utf-?8\s*)?$/i,
42      mime,
43    ) !== null
44  ) { return 'module'; }
45  if (mime === 'application/json') { return 'json'; }
46  if (experimentalWasmModules && mime === 'application/wasm') { return 'wasm'; }
47  return null;
48}
49
50function getLegacyExtensionFormat(ext) {
51  return legacyExtensionFormatMap[ext];
52}
53
54/**
55 * For extensionless files in a `module` package scope, or a default `module` scope enabled by the
56 * `--experimental-default-type` flag, we check the file contents to disambiguate between ES module JavaScript and Wasm.
57 * We do this by taking advantage of the fact that all Wasm files start with the header `0x00 0x61 0x73 0x6d` (`_asm`).
58 * @param {URL} url
59 */
60function getFormatOfExtensionlessFile(url) {
61  if (!experimentalWasmModules) { return 'module'; }
62
63  const magic = new Uint8Array(4);
64  let fd;
65  try {
66    // TODO(@anonrig): Optimize the following by having a single C++ call
67    fd = openSync(url);
68    readSync(fd, magic, 0, 4); // Only read the first four bytes
69    if (magic[0] === 0x00 && magic[1] === 0x61 && magic[2] === 0x73 && magic[3] === 0x6d) {
70      return 'wasm';
71    }
72  } finally {
73    if (fd !== undefined) { closeSync(fd); }
74  }
75
76  return 'module';
77}
78
79module.exports = {
80  extensionFormatMap,
81  getFormatOfExtensionlessFile,
82  getLegacyExtensionFormat,
83  legacyExtensionFormatMap,
84  mimeToFormat,
85};
86