UNPKG

4.86 kBJavaScriptView Raw
1/**
2 * @license
3 * Copyright (c) 2018 The Polymer Project Authors. All rights reserved.
4 * This code may only be used under the BSD style license found at
5 * http://polymer.github.io/LICENSE.txt
6 * The complete set of authors may be found at
7 * http://polymer.github.io/AUTHORS.txt
8 * The complete set of contributors may be found at
9 * http://polymer.github.io/CONTRIBUTORS.txt
10 * Code distributed by Google as part of the polymer project is also
11 * subject to an additional IP rights grant found at
12 * http://polymer.github.io/PATENTS.txt
13 */
14
15const {dirname, relative} = require('path');
16const resolve = require('resolve');
17const {NodePath} = require('babel-traverse');
18const isWindows = require('is-windows');
19const whatwgUrl = require('whatwg-url');
20const {ImportDeclaration, ExportNamedDeclaration, ExportAllDeclaration} = require('babel-types');
21
22const exportExtensions = require('babel-plugin-syntax-export-extensions');
23
24const isPathSpecifier = (s) => /^\.{0,2}\//.test(s);
25
26/**
27 * Rewrites so-called "bare module specifiers" to be web-compatible paths.
28 */
29const resolveBareSpecifiers =
30 (filePath, isComponentRequest) => ({
31 inherits: exportExtensions,
32 visitor: {
33 'ImportDeclaration|ExportNamedDeclaration|ExportAllDeclaration'(
34 path) {
35 const node = path.node;
36
37 // An export without a 'from' clause
38 if (node.source == null) {
39 return;
40 }
41
42 const specifier = node.source.value;
43
44 if (whatwgUrl.parseURL(specifier) !== null) {
45 return;
46 }
47
48 if (isPathSpecifier(specifier)) {
49 return;
50 }
51
52 const newSpecifier =
53 specifier === 'assert' ? 'assert-es-module' :
54 specifier === 'buffer' ? 'buffer-es-module' :
55 specifier === 'console' ? 'console-browserify-es-module' :
56 specifier === 'constants' ? 'constants-browserify-es-module' :
57 specifier === 'crypto' ? 'crypto-browserify-es-module' :
58 specifier === 'domain' ? 'domain-browser-es-module' :
59 specifier === 'events' ? 'events-es-module' :
60 specifier === 'http' ? 'http-browserify-es-module' :
61 specifier === 'https' ? 'https-browserify-es-module' :
62 specifier === 'os' ? 'os-browserify-es-module' :
63 specifier === 'path' ? 'path-browserify-es-module' :
64 specifier === 'punycode' ? 'punycode-es-module' :
65 specifier === 'querystring' ? 'querystring-es-module' :
66 specifier === 'stream' ? 'stream-es-module' :
67 specifier === 'string_decoder' ? 'string_decoder-es-module' :
68 specifier === 'timers' ? 'timers-browserify-es-module' :
69 specifier === 'tty' ? 'tty-browserify-es-module' :
70 specifier === 'url' ? 'url-es-module' :
71 specifier === 'util' ? 'util-es-module' :
72 specifier === 'vm' ? 'vm-browserify-es-module' :
73 specifier === 'zlib' ? 'browserify-zlib-es-module' :
74 specifier === 'fs' ? 'browserify-fs-es-module' :
75 specifier === 'inherits' ? 'inherits-es-module' : specifier;
76
77 const resolvedSpecifier = resolve.sync(newSpecifier, {
78 basedir: filePath,
79 // Some packages use a non-standard alternative to the "main" field
80 // in their package.json to differentiate their ES module version.
81 packageFilter: (packageJson) => {
82 packageJson.main = packageJson.module ||
83 packageJson['jsnext:main'] || packageJson.main;
84 return packageJson;
85 },
86 });
87
88 let relativeSpecifierUrl =
89 relative(dirname(filePath), resolvedSpecifier);
90
91 if (isWindows()) {
92 relativeSpecifierUrl = relativeSpecifierUrl.replace(/\\/g, '/');
93 }
94
95 if (!isPathSpecifier(relativeSpecifierUrl)) {
96 relativeSpecifierUrl = './' + relativeSpecifierUrl;
97 }
98 if (isComponentRequest &&
99 relativeSpecifierUrl.startsWith('../node_modules/')) {
100 // Remove ../node_modules for component serving
101 relativeSpecifierUrl = '../' +
102 relativeSpecifierUrl.substring('../node_modules/'.length);
103 }
104 node.source.value = relativeSpecifierUrl;
105 }
106 }
107 });
108
109module.exports = resolveBareSpecifiers;