UNPKG

16.4 kBJavaScriptView Raw
1"use strict";
2/**
3 * @license
4 * Copyright (c) 2018 The Polymer Project Authors. All rights reserved.
5 * This code may only be used under the BSD style license found at
6 * http://polymer.github.io/LICENSE.txt
7 * The complete set of authors may be found at
8 * http://polymer.github.io/AUTHORS.txt
9 * The complete set of contributors may be found at
10 * http://polymer.github.io/CONTRIBUTORS.txt
11 * Code distributed by Google as part of the polymer project is also
12 * subject to an additional IP rights grant found at
13 * http://polymer.github.io/PATENTS.txt
14 */
15var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
16 return new (P || (P = Promise))(function (resolve, reject) {
17 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
18 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
19 function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
20 step((generator = generator.apply(thisArg, _arguments || [])).next());
21 });
22};
23Object.defineProperty(exports, "__esModule", { value: true });
24const chai_1 = require("chai");
25const path = require("path");
26const stripIndent = require("strip-indent");
27const js_transform_1 = require("../js-transform");
28const util_1 = require("./util");
29suite('jsTransform', () => {
30 const rootDir = path.join(__dirname, '..', '..', 'test-fixtures', 'npm-modules');
31 const filePath = path.join(rootDir, 'foo.js');
32 suite('compilation', () => {
33 test('compiles to ES5 when compile=true', () => {
34 chai_1.assert.equal(js_transform_1.jsTransform('const foo = 3;', { compile: true }), 'var foo = 3;');
35 });
36 test('compiles to ES5 when compile=es5', () => {
37 chai_1.assert.equal(js_transform_1.jsTransform('const foo = 3;', { compile: 'es5' }), 'var foo = 3;');
38 });
39 test('compiles to ES2015 when compile=es2015', () => {
40 chai_1.assert.equal(js_transform_1.jsTransform('2 ** 5;', { compile: 'es2015' }), 'Math.pow(2, 5);');
41 });
42 test('compiles ES2017 to ES5', () => __awaiter(this, void 0, void 0, function* () {
43 const result = js_transform_1.jsTransform('async function test() { await 0; }', { compile: 'es5' });
44 chai_1.assert.include(result, '_asyncToGenerator');
45 chai_1.assert.notInclude(result, 'async function test');
46 chai_1.assert.include(result, 'regeneratorRuntime');
47 }));
48 test('compiles ES2017 to ES2015', () => __awaiter(this, void 0, void 0, function* () {
49 const result = js_transform_1.jsTransform('async function test() { await 0; }', { compile: 'es2015' });
50 chai_1.assert.include(result, 'asyncToGenerator');
51 chai_1.assert.notInclude(result, 'async function test');
52 chai_1.assert.notInclude(result, 'regeneratorRuntime');
53 }));
54 test('does not unnecessarily reformat', () => {
55 // Even with no transform plugins, parsing and serializing with Babel will
56 // make some minor formatting changes to the code, such as removing
57 // trailing newlines. Check that we don't do this when no transformations
58 // were configured.
59 chai_1.assert.equal(js_transform_1.jsTransform('const foo = 3;\n', {}), 'const foo = 3;\n');
60 });
61 });
62 suite('minification', () => {
63 test('minifies a simple expression', () => {
64 chai_1.assert.equal(js_transform_1.jsTransform('const foo = 3;', { minify: true }), 'const foo=3;');
65 });
66 test('minifies an exported const', () => {
67 chai_1.assert.equal(js_transform_1.jsTransform('const foo = "foo"; export { foo };', { minify: true }), 'const foo="foo";export{foo};');
68 });
69 test('minifies and compiles', () => {
70 chai_1.assert.equal(js_transform_1.jsTransform('const foo = 3;', { compile: true, minify: true }), 'var foo=3;');
71 });
72 test('minifies but does not try to remove dead code', () => {
73 chai_1.assert.equal(js_transform_1.jsTransform('if (false) { never(); } always();', { minify: true }), 'if(!1){never()}always();');
74 });
75 });
76 suite('babel helpers', () => {
77 const classJs = `class MyClass {}`;
78 const helperSnippet = `function _classCallCheck(`;
79 test('inlined when external helpers are disabled', () => {
80 const result = js_transform_1.jsTransform(classJs, { compile: true, externalHelpers: false });
81 chai_1.assert.include(result, helperSnippet);
82 chai_1.assert.include(result, 'MyClass');
83 });
84 test('omitted when external helpers are enabled', () => {
85 const result = js_transform_1.jsTransform(classJs, { compile: true, externalHelpers: true });
86 chai_1.assert.notInclude(result, helperSnippet);
87 chai_1.assert.include(result, 'MyClass');
88 });
89 });
90 suite('regenerator runtime', () => {
91 const asyncJs = `async () => { await myFunction(); } `;
92 const regeneratorSnippet = `regeneratorRuntime=`;
93 test('inlined when external helpers are disabled', () => {
94 const result = js_transform_1.jsTransform(asyncJs, { compile: 'es5', externalHelpers: false });
95 chai_1.assert.include(result, regeneratorSnippet);
96 chai_1.assert.include(result, 'myFunction');
97 });
98 test('omitted when external helpers are enabled', () => {
99 const result = js_transform_1.jsTransform(asyncJs, { compile: 'es5', externalHelpers: true });
100 chai_1.assert.notInclude(result, regeneratorSnippet);
101 chai_1.assert.include(result, 'myFunction');
102 });
103 test('omitted when compile target is es2015', () => {
104 const result = js_transform_1.jsTransform(asyncJs, { compile: 'es2015', externalHelpers: false });
105 chai_1.assert.notInclude(result, regeneratorSnippet);
106 chai_1.assert.include(result, 'myFunction');
107 });
108 test('omitted when code does not require it', () => {
109 const result = js_transform_1.jsTransform(`class MyClass {}`, { compile: 'es5', externalHelpers: false });
110 chai_1.assert.notInclude(result, regeneratorSnippet);
111 chai_1.assert.include(result, 'MyClass');
112 });
113 });
114 suite('parse errors', () => {
115 const invalidJs = ';var{';
116 test('throw when softSyntaxError is false', () => {
117 chai_1.assert.throws(() => js_transform_1.jsTransform(invalidJs, { compile: true, softSyntaxError: false }));
118 });
119 test('do not throw when softSyntaxError is true', () => __awaiter(this, void 0, void 0, function* () {
120 const output = yield util_1.interceptOutput(() => __awaiter(this, void 0, void 0, function* () {
121 chai_1.assert.equal(js_transform_1.jsTransform(invalidJs, { compile: true, softSyntaxError: true }), invalidJs);
122 }));
123 chai_1.assert.include(output, '[polymer-build]: failed to parse JavaScript:');
124 }));
125 });
126 suite('exponentiation', () => {
127 const js = 'const foo = 2**2;';
128 test('minifies', () => {
129 chai_1.assert.equal(js_transform_1.jsTransform(js, { minify: true }), 'const foo=2**2;');
130 });
131 test('compiles to ES5', () => {
132 chai_1.assert.equal(js_transform_1.jsTransform(js, { compile: true }), 'var foo = Math.pow(2, 2);');
133 });
134 });
135 suite('rest properties', () => {
136 const js = 'let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };';
137 test('minifies', () => {
138 chai_1.assert.equal(js_transform_1.jsTransform(js, { minify: true }), 'let{x,y,...z}={x:1,y:2,a:3,b:4};');
139 });
140 test('compiles to ES5', () => {
141 chai_1.assert.include(js_transform_1.jsTransform(js, { compile: true }),
142 // Some compiled features are very verbose. Just look for the Babel
143 // helper call so we know the plugin ran.
144 'objectWithoutProperties');
145 });
146 });
147 suite('spread properties', () => {
148 const js = 'let n = { x, y, ...z };';
149 test('minifies', () => {
150 chai_1.assert.equal(js_transform_1.jsTransform(js, { minify: true }), 'let n={x,y,...z};');
151 });
152 test('compiles to ES5', () => {
153 chai_1.assert.include(js_transform_1.jsTransform(js, { compile: true }), 'objectSpread');
154 });
155 });
156 suite('async/await', () => {
157 const js = 'async function foo() { await bar(); }';
158 test('minifies', () => {
159 chai_1.assert.equal(js_transform_1.jsTransform(js, { minify: true }), 'async function foo(){await bar()}');
160 });
161 test('compiles to ES5', () => {
162 chai_1.assert.include(js_transform_1.jsTransform(js, { compile: true }), 'asyncToGenerator');
163 });
164 });
165 suite('async generator', () => {
166 const js = 'async function* foo() { yield bar; }';
167 test('minifies', () => {
168 chai_1.assert.equal(js_transform_1.jsTransform(js, { minify: true }), 'async function*foo(){yield bar}');
169 });
170 test('compiles to ES5', () => {
171 chai_1.assert.include(js_transform_1.jsTransform(js, { compile: true }), 'wrapAsyncGenerator');
172 });
173 });
174 suite('dynamic import', () => {
175 const js = 'const foo = import("bar.js");';
176 test('minifies', () => {
177 chai_1.assert.equal(js_transform_1.jsTransform(js, { minify: true }), 'const foo=import("bar.js");');
178 });
179 });
180 suite('rewrites bare module specifiers', () => {
181 test('node packages', () => {
182 const input = stripIndent(`
183 import { dep1 } from 'dep1';
184 import { dep2 } from 'dep2';
185 import { dep2A } from 'dep2/a';
186 import { dep3 } from 'dep3';
187 import { dep4 } from 'dep4';
188 `);
189 const expected = stripIndent(`
190 import { dep1 } from "./node_modules/dep1/index.js";
191 import { dep2 } from "./node_modules/dep2/dep2.js";
192 import { dep2A } from "./node_modules/dep2/a.js";
193 import { dep3 } from "./node_modules/dep3/dep3-module.js";
194 import { dep4 } from "./node_modules/dep4/dep4-module.js";
195 `);
196 const result = js_transform_1.jsTransform(input, { moduleResolution: 'node', filePath });
197 chai_1.assert.equal(result.trim(), expected.trim());
198 });
199 test('regular paths and urls', () => {
200 const input = stripIndent(`
201 import { p1 } from '/already/a/path.js';
202 import { p2 } from './already/a/path.js';
203 import { p3 } from '../already/a/path.js';
204 import { p4 } from '../already/a/path.js';
205 import { p5 } from 'http://example.com/already/a/path.js';
206 `);
207 const expected = stripIndent(`
208 import { p1 } from '/already/a/path.js';
209 import { p2 } from './already/a/path.js';
210 import { p3 } from '../already/a/path.js';
211 import { p4 } from '../already/a/path.js';
212 import { p5 } from 'http://example.com/already/a/path.js';
213 `);
214 const result = js_transform_1.jsTransform(input, { moduleResolution: 'node', filePath });
215 chai_1.assert.equal(result.trim(), expected.trim());
216 });
217 test('paths that still need node resolution', () => {
218 const input =
219 // Resolves to a .js file.
220 `import { bar } from './bar';\n` +
221 // Resolves to a .json file (invalid for the web, but we still do it).
222 `import { baz } from './baz';\n` +
223 // Resolves to an actual extension-less file in preference to a .js
224 // file with the same basename.
225 `import { qux } from './qux';\n`;
226 const expected = stripIndent(`
227 import { bar } from "./bar.js";
228 import { baz } from "./baz.json";
229 import { qux } from './qux';
230 `);
231 const result = js_transform_1.jsTransform(input, { moduleResolution: 'node', filePath });
232 chai_1.assert.equal(result.trim(), expected.trim());
233 });
234 test('paths for dependencies', () => {
235 const input = stripIndent(`
236 import { dep1 } from 'dep1';
237 `);
238 const expected = stripIndent(`
239 import { dep1 } from "../dep1/index.js";
240 `);
241 const result = js_transform_1.jsTransform(input, {
242 moduleResolution: 'node',
243 filePath,
244 isComponentRequest: true,
245 packageName: 'some-package',
246 componentDir: path.join(rootDir, 'node_modules'),
247 rootDir,
248 });
249 chai_1.assert.equal(result.trim(), expected.trim());
250 });
251 test('dependencies from a scoped package', () => {
252 const input = stripIndent(`
253 import { dep1 } from 'dep1';
254 `);
255 const expected = stripIndent(`
256 import { dep1 } from "../../dep1/index.js";
257 `);
258 const result = js_transform_1.jsTransform(input, {
259 moduleResolution: 'node',
260 filePath,
261 isComponentRequest: true,
262 packageName: '@some-scope/some-package',
263 componentDir: path.join(rootDir, 'node_modules'),
264 rootDir,
265 });
266 chai_1.assert.equal(result.trim(), expected.trim());
267 });
268 });
269 test('transforms ES modules to AMD', () => {
270 const input = stripIndent(`
271 import { dep1 } from 'dep1';
272 export const foo = 'foo';
273 `);
274 const expected = stripIndent(`
275 define(["exports", "dep1"], function (_exports, _dep) {
276 "use strict";
277
278 Object.defineProperty(_exports, "__esModule", {
279 value: true
280 });
281 _exports.foo = void 0;
282 const foo = 'foo';
283 _exports.foo = foo;
284 });
285 `);
286 const result = js_transform_1.jsTransform(input, {
287 transformModulesToAmd: true,
288 filePath,
289 rootDir,
290 });
291 chai_1.assert.equal(result.trim(), expected.trim());
292 });
293 test('transforms import.meta', () => {
294 const input = stripIndent(`
295 console.log(import.meta);
296 `);
297 const expected = stripIndent(`
298 define(["meta"], function (meta) {
299 "use strict";
300
301 meta = babelHelpers.interopRequireWildcard(meta);
302 console.log(meta);
303 });
304 `);
305 const result = js_transform_1.jsTransform(input, {
306 transformModulesToAmd: true,
307 externalHelpers: true,
308 });
309 chai_1.assert.equal(result.trim(), expected.trim());
310 });
311 test('transforms dynamic import()', () => {
312 const input = stripIndent(`
313 import { dep1 } from 'dep1';
314 export const foo = 'foo';
315 console.log(import('./bar.js'));
316 `);
317 const result = js_transform_1.jsTransform(input, {
318 transformModulesToAmd: true,
319 filePath,
320 rootDir,
321 });
322 chai_1.assert.include(result, `define(["exports", "require", "dep1"], function (_exports, _require, _dep) {`);
323 chai_1.assert.include(result, `console.log(new Promise((res, rej) => _require.default(['./bar.js'], res, rej)));`);
324 });
325 // https://github.com/babel/babel/pull/8501
326 test('includes the native function check', () => {
327 const input = stripIndent(`
328 class TestElement extends HTMLElement {
329 constructor() {
330 super();
331 this.x = 1234;
332 }
333 }
334
335 window.customElements.define("test-element", TestElement);
336 `);
337 const result = js_transform_1.jsTransform(input, { compile: true });
338 chai_1.assert.include(result, '_isNativeFunction');
339 });
340 // https://github.com/babel/minify/issues/824
341 test('does not remove statements preceding certain loops', () => {
342 const input = stripIndent(`
343 let foo = 'bar';
344 while (0);
345 console.log(foo);
346 `);
347 const result = js_transform_1.jsTransform(input, { compile: true, minify: true });
348 chai_1.assert.include(result, 'bar');
349 });
350});
351//# sourceMappingURL=js-transform_test.js.map
\No newline at end of file