UNPKG

3.46 kBPlain TextView 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
15import dynamicImportSyntax from '@babel/plugin-syntax-dynamic-import';
16import {NodePath} from '@babel/traverse';
17import {CallExpression, ExportAllDeclaration, ExportNamedDeclaration, ImportDeclaration, Program} from 'babel-types';
18import {resolve} from 'polymer-analyzer/lib/javascript/resolve-specifier-node';
19
20const isPathSpecifier = (s: string) => /^\.{0,2}\//.test(s);
21
22type HasSpecifier =
23 ImportDeclaration|ExportNamedDeclaration|ExportAllDeclaration;
24
25/**
26 * Rewrites so-called "bare module specifiers" to be web-compatible paths.
27 */
28export const resolveBareSpecifiers = (
29 filePath: string,
30 isComponentRequest: boolean,
31 packageName?: string,
32 componentDir?: string,
33 rootDir?: string,
34 ) => ({
35 inherits: dynamicImportSyntax,
36
37 visitor: {
38 Program(path: NodePath<Program>) {
39 path.traverse({
40 CallExpression(path: NodePath<CallExpression>) {
41 if (path.node.callee.type as string === 'Import') {
42 const specifierArg = path.node.arguments[0];
43 if (specifierArg.type !== 'StringLiteral') {
44 // Should never happen
45 return;
46 }
47 const specifier = specifierArg.value;
48 specifierArg.value = maybeResolve(
49 specifier,
50 filePath,
51 isComponentRequest,
52 packageName,
53 componentDir,
54 rootDir);
55 }
56 }
57 });
58 },
59 'ImportDeclaration|ExportNamedDeclaration|ExportAllDeclaration'(
60 path: NodePath<HasSpecifier>) {
61 const node = path.node;
62
63 // An export without a 'from' clause
64 if (node.source == null) {
65 return;
66 }
67
68 const specifier = node.source.value;
69 node.source.value = maybeResolve(
70 specifier,
71 filePath,
72 isComponentRequest,
73 packageName,
74 componentDir,
75 rootDir);
76 }
77 }
78});
79
80const maybeResolve = (
81 specifier: string,
82 filePath: string,
83 isComponentRequest: boolean,
84 packageName?: string,
85 componentDir?: string,
86 rootDir?: string,
87 ) => {
88 try {
89 let componentInfo;
90 if (isComponentRequest) {
91 componentInfo = {
92 packageName: packageName!,
93 componentDir: componentDir!,
94 rootDir: rootDir!,
95 };
96 }
97 return resolve(specifier, filePath, componentInfo);
98 } catch (e) {
99 // `require` and `meta` are fake imports that our other build tooling
100 // injects, so we should not warn for them.
101 if (!isPathSpecifier(specifier) && specifier !== 'require' &&
102 specifier !== 'meta') {
103 // Don't warn if the specifier was already a path, even though we do
104 // resolve paths, because maybe the user is serving it some other
105 // way.
106 console.warn(
107 `Could not resolve module specifier "${specifier}" ` +
108 `in file "${filePath}".`);
109 }
110 return specifier;
111 }
112};