diff --git a/package.json b/package.json index ee170ea2..c67a1966 100644 --- a/package.json +++ b/package.json @@ -39,13 +39,14 @@ "acorn-walk": "7.0.0", "google-closure-compiler": "20200101.0.0", "magic-string": "0.25.5", - "temp-write": "4.0.0" + "uuid": "3.3.3" }, "devDependencies": { "@types/acorn": "4.0.5", "@types/estree": "0.0.41", "@types/node": "12.12.24", "@types/temp-write": "3.3.0", + "@types/uuid": "3.4.6", "ava": "2.4.0", "builtins": "3.0.0", "c8": "7.0.0", diff --git a/src/debug.ts b/src/debug.ts index 369ba823..3e54c051 100644 --- a/src/debug.ts +++ b/src/debug.ts @@ -14,17 +14,20 @@ * limitations under the License. */ -import { sync } from 'temp-write'; +import { writeTempFile } from './temp-file'; const DEBUG_ENABLED = false; -/* c8 ignore next 9 */ -export const logSource = (preamble: string, source: string, code?: string) => { +/* c8 ignore next 12 */ +export const logSource = async (preamble: string, source: string, code?: string): Promise => { if (DEBUG_ENABLED) { + const sourceLocation: string = await writeTempFile(source); + const codeLocation: string = code ? await writeTempFile(code) : ''; + console.log(preamble); - console.log(sync(source)); + console.log(sourceLocation); if (code) { - console.log(sync(code)); + console.log(codeLocation); } } }; diff --git a/src/index.ts b/src/index.ts index bf433ae2..ed7eb378 100644 --- a/src/index.ts +++ b/src/index.ts @@ -44,7 +44,7 @@ const renderChunk = async ( outputOptions: OutputOptions, ): Promise<{ code: string; map: SourceMapInput } | void> => { const code = await preCompilation(sourceCode, outputOptions, transforms); - const [compileOptions, mapFile] = options( + const [compileOptions, mapFile] = await options( requestedCompileOptions, outputOptions, code, diff --git a/src/options.ts b/src/options.ts index 8f634ccd..f1a78050 100644 --- a/src/options.ts +++ b/src/options.ts @@ -17,7 +17,7 @@ import { Transform } from './types'; import { ModuleFormat, OutputOptions } from 'rollup'; import { CompileOptions } from 'google-closure-compiler'; -import { sync } from 'temp-write'; +import { writeTempFile } from './temp-file'; import { log } from './debug'; export const ERROR_WARNINGS_ENABLED_LANGUAGE_OUT_UNSPECIFIED = @@ -54,11 +54,11 @@ function validateCompileOptions(compileOptions: CompileOptions): void { * @param options * @return derived CompileOptions for Closure Compiler */ -export const defaults = ( +export const defaults = async ( options: OutputOptions, providedExterns: Array, transformers: Array | null, -): CompileOptions => { +): Promise => { // Defaults for Rollup Projects are slightly different than Closure Compiler defaults. // - Users of Rollup tend to transpile their code before handing it to a minifier, // so no transpile is default. @@ -69,7 +69,7 @@ export const defaults = ( for (const transform of transformers || []) { const extern = transform.extern(options); if (extern !== null) { - transformerExterns.push(sync(extern)); + transformerExterns.push(await writeTempFile(extern)); } } @@ -91,13 +91,13 @@ export const defaults = ( * @param code * @param transforms */ -export default function( +export default async function( incomingCompileOptions: CompileOptions, outputOptions: OutputOptions, code: string, transforms: Array | null, -): [CompileOptions, string] { - const mapFile: string = sync(''); +): Promise<[CompileOptions, string]> { + const mapFile: string = await writeTempFile(''); const compileOptions: CompileOptions = { ...incomingCompileOptions }; let externs: Array = []; @@ -119,9 +119,9 @@ export default function( } const options = { - ...defaults(outputOptions, externs, transforms), + ...(await defaults(outputOptions, externs, transforms)), ...compileOptions, - js: sync(code), + js: await writeTempFile(code), create_source_map: mapFile, }; diff --git a/src/temp-file.ts b/src/temp-file.ts new file mode 100644 index 00000000..64fdca89 --- /dev/null +++ b/src/temp-file.ts @@ -0,0 +1,28 @@ +/** + * Copyright 2020 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { join, dirname } from 'path'; +import { tmpdir } from 'os'; +import { v4 } from 'uuid'; +import { promises } from 'fs'; + +export async function writeTempFile(content: string): Promise { + const path: string = join(tmpdir(), v4(), ''); + await promises.mkdir(dirname(path), { recursive: true }); + await promises.writeFile(path, content, 'utf-8'); + + return path; +} diff --git a/src/transforms.ts b/src/transforms.ts index 3ca2e4c6..5d6327b0 100644 --- a/src/transforms.ts +++ b/src/transforms.ts @@ -60,7 +60,7 @@ export async function preCompilation( ): Promise { // Each transform has a 'preCompilation' step that must complete before passing // the resulting code to Closure Compiler. - logSource('before preCompilation handlers', code); + await logSource('before preCompilation handlers', code); for (const transform of transforms) { transform.outputOptions = outputOptions; const result = await transform.preCompilation(code); @@ -70,7 +70,7 @@ export async function preCompilation( } } - logSource('after preCompilation handlers', code); + await logSource('after preCompilation handlers', code); return code; } @@ -83,7 +83,7 @@ export async function preCompilation( export async function postCompilation(code: string, transforms: Array): Promise { // Following successful Closure Compiler compilation, each transform needs an opportunity // to clean up work is performed in preCompilation via postCompilation. - logSource('before postCompilation handlers', code); + await logSource('before postCompilation handlers', code); for (const transform of transforms) { const result = await transform.postCompilation(code); if (result && result.code) { @@ -92,6 +92,6 @@ export async function postCompilation(code: string, transforms: Array } } - logSource('after postCompilation handlers', code); + await logSource('after postCompilation handlers', code); return code; } diff --git a/test/closure-config/prefer-config.test.js b/test/closure-config/prefer-config.test.js index 350c7365..5115683d 100644 --- a/test/closure-config/prefer-config.test.js +++ b/test/closure-config/prefer-config.test.js @@ -18,14 +18,14 @@ import test from 'ava'; import options from '../../transpile-tests/options'; import { generator } from '../generator'; -test('platform unspecified is respected', t => { - const typical = options({}, 'let x = 1;', []); +test('platform unspecified is respected', async t => { + const typical = await options({}, 'let x = 1;', []); t.is(typical[0].platform, undefined); }); -test('platform javascript is respected', t => { - const javascriptPlatform = options( +test('platform javascript is respected', async t => { + const javascriptPlatform = await options( { platform: 'javascript', }, diff --git a/test/closure-config/rollup-config-externs.test.js b/test/closure-config/rollup-config-externs.test.js index 73cd1a43..d004a731 100644 --- a/test/closure-config/rollup-config-externs.test.js +++ b/test/closure-config/rollup-config-externs.test.js @@ -36,19 +36,20 @@ const IifeTransform = class { test('when rollup configuration specifies externs, extern is leveraged', async t => { t.plan(3); - const compilerOptionsExterns = compile({ + const compiled = await compile({ externs: PROVIDED_EXTERN, }, { format: 'iife', name: 'wrapper', - }, 'var x = 1;', [new IifeTransform()])[0].externs; + }, 'var x = 1;', [new IifeTransform()]); + const externs = compiled[0].externs; - t.is(compilerOptionsExterns.length, 2); - t.true(compilerOptionsExterns.includes(PROVIDED_EXTERN)); + t.is(externs.length, 2); + t.true(externs.includes(PROVIDED_EXTERN)); // While we can use the path for the provided extern, we need to inspect the content of // the other extern to ensure it is the generated extern. // Externs are passed as filepaths to Closure Compiler. - const fileContent = await fsPromises.readFile(compilerOptionsExterns.filter(path => path !== PROVIDED_EXTERN)[0], 'utf8'); + const fileContent = await fsPromises.readFile(externs.filter(path => path !== PROVIDED_EXTERN)[0], 'utf8'); t.true(fileContent === IIFE_TRANSFORM_EXTERN_CONTENT); }); diff --git a/test/closure-config/rollup-config-to-flags.test.js b/test/closure-config/rollup-config-to-flags.test.js index da58cf8e..200934f5 100644 --- a/test/closure-config/rollup-config-to-flags.test.js +++ b/test/closure-config/rollup-config-to-flags.test.js @@ -17,10 +17,10 @@ import test from 'ava'; import { defaults } from '../../transpile-tests/options'; -test.beforeEach(t => { +test.beforeEach(async t => { t.context = { - default: defaults({}, [], null), - esOutput: defaults({ + default: await defaults({}, [], null), + esOutput: await defaults({ format: 'es', }, [], null), }; diff --git a/test/closure-config/warning-level.test.js b/test/closure-config/warning-level.test.js index 8fa3d8ee..9a119b11 100644 --- a/test/closure-config/warning-level.test.js +++ b/test/closure-config/warning-level.test.js @@ -17,9 +17,9 @@ import test from 'ava'; import compile, {ERROR_WARNINGS_ENABLED_LANGUAGE_OUT_UNSPECIFIED, ERROR_WARNINGS_ENABLED_LANGUAGE_OUT_INVALID} from '../../transpile-tests/options'; -test('with no language out set, and warnings set to verbose... an error is returned', t => { +test('with no language out set, and warnings set to verbose... an error is returned', async t => { try { - compile({ + await compile({ warning_level: 'VERBOSE', }, { format: 'es', @@ -31,9 +31,9 @@ test('with no language out set, and warnings set to verbose... an error is retur } }); -test('with language out set to no_transpile, and warnings set to verbose... an error is returned', t => { +test('with language out set to no_transpile, and warnings set to verbose... an error is returned', async t => { try { - compile({ + await compile({ warning_level: 'VERBOSE', language_out: 'NO_TRANSPILE', }, { diff --git a/test/export-cjs/export-cjs-extern.test.js b/test/export-cjs/export-cjs-extern.test.js index 3d726732..34960272 100644 --- a/test/export-cjs/export-cjs-extern.test.js +++ b/test/export-cjs/export-cjs-extern.test.js @@ -26,7 +26,7 @@ test('generate extern for cjs export pattern', async t => { }; const transforms = createTransforms({}); - const options = defaults(outputOptions, [], transforms); + const options = await defaults(outputOptions, [], transforms); for (const externFilePath of options.externs) { const fileContent = await fsPromises.readFile(externFilePath, 'utf8'); diff --git a/test/iife/iife-wrapped-safely.test.js b/test/iife/iife-wrapped-safely.test.js index d7119a1b..ce633c51 100644 --- a/test/iife/iife-wrapped-safely.test.js +++ b/test/iife/iife-wrapped-safely.test.js @@ -31,7 +31,7 @@ test('generate extern for iife name', async t => { }; const transforms = createTransforms({}); - const options = defaults(outputOptions, [], transforms); + const options = await defaults(outputOptions, [], transforms); for (const externFilePath of options.externs) { const fileContent = await fsPromises.readFile(externFilePath, 'utf8'); diff --git a/yarn.lock b/yarn.lock index 518876be..785de5ca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -428,6 +428,13 @@ dependencies: "@types/node" "*" +"@types/uuid@3.4.6": + version "3.4.6" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.6.tgz#d2c4c48eb85a757bf2927f75f939942d521e3016" + integrity sha512-cCdlC/1kGEZdEglzOieLDYBxHsvEOIg7kp/2FYyVR9Pxakq+Qf/inL3RKQ+PA8gOlI/NnL+fXmQH12nwcGzsHw== + dependencies: + "@types/node" "*" + acorn-dynamic-import@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz#482210140582a36b83c3e342e1cfebcaa9240948" @@ -3990,22 +3997,6 @@ teeny-request@^3.11.3: node-fetch "^2.2.0" uuid "^3.3.2" -temp-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" - integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0= - -temp-write@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/temp-write/-/temp-write-4.0.0.tgz#cd2e0825fc826ae72d201dc26eef3bf7e6fc9320" - integrity sha512-HIeWmj77uOOHb0QX7siN3OtwV3CTntquin6TNVg6SHOqCP3hYKmox90eeFOGaY1MqJ9WYDDjkyZrW6qS5AWpbw== - dependencies: - graceful-fs "^4.1.15" - is-stream "^2.0.0" - make-dir "^3.0.0" - temp-dir "^1.0.0" - uuid "^3.3.2" - term-size@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" @@ -4208,7 +4199,7 @@ util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -uuid@^3.3.2: +uuid@3.3.3, uuid@^3.3.2: version "3.3.3" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==