Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More

@ampproject/rollup-plugin-closure-compiler

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ampproject/rollup-plugin-closure-compiler - npm Package Compare versions

Comparing version 0.18.1 to 0.19.0

@@ -8,4 +8,5 @@ 'use strict';

var MagicString = _interopDefault(require('magic-string'));
var tempWrite = require('temp-write');
var path = require('path');
var os = require('os');
var uuid = require('uuid');

@@ -52,3 +53,3 @@ /**

extern(options) {
return '';
return null;
}

@@ -103,3 +104,3 @@ async preCompilation(code) {

}
return '';
return null;
}

@@ -109,2 +110,47 @@ }

/**
* 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.
*/
const HEADER$1 = `/**
* @fileoverview Externs built via derived configuration from Rollup or input code.
* This extern contains the cjs typing info for modules.
* @externs
*/
/**
* @typedef {{
* __esModule: boolean,
* }}
*/
var exports;`;
/**
* This Transform will apply only if the Rollup configuration is for a cjs output.
*
* In order to preserve the __esModules boolean on an Object, this typedef needs to be present.
*/
class CJSTransform extends Transform {
constructor() {
super(...arguments);
this.name = 'CJSTransform';
}
extern(options) {
if (options.format === 'cjs') {
return HEADER$1;
}
return null;
}
}
/**
* Copyright 2018 The AMP HTML Authors. All Rights Reserved.

@@ -184,11 +230,9 @@ *

ObjectExpression(node) {
const properties = node.properties;
properties.forEach(property => {
if (property.computed &&
property.key.type === 'Literal' &&
property.range &&
property.value.range) {
source.overwrite(property.range[0], property.value.range[0], `${property.key.value}${property.value.type !== 'FunctionExpression' ? ':' : ''}`);
for (const property of node.properties) {
const [propertyStart] = property.range;
const [valueStart] = property.value.range;
if (property.computed && property.key.type === 'Literal') {
source.overwrite(propertyStart, valueStart, `${property.key.value}${property.value.type !== 'FunctionExpression' ? ':' : ''}`);
}
});
}
},

@@ -204,3 +248,3 @@ });

/**
* Copyright 2018 The AMP HTML Authors. All Rights Reserved.
* Copyright 2020 The AMP HTML Authors. All Rights Reserved.
*

@@ -219,64 +263,161 @@ * Licensed under the Apache License, Version 2.0 (the "License");

*/
function NamedDeclaration(context, declaration) {
const range = declaration.range;
const source = declaration.source && declaration.source.value && typeof declaration.source.value === 'string'
? declaration.source.value
: null;
if (declaration.specifiers) {
const exportDetails = [];
for (const specifier of declaration.specifiers) {
exportDetails.push({
local: specifier.local.name,
exported: specifier.exported.name,
closureName: specifier.exported.name,
type: ExportClosureMapping.NAMED_CONSTANT,
range,
source,
});
}
return exportDetails;
function NamedDeclaration(declaration) {
var _a, _b;
const exportDetails = [];
const source = typeof ((_b = (_a = declaration) === null || _a === void 0 ? void 0 : _a.source) === null || _b === void 0 ? void 0 : _b.value) === 'string' ? declaration.source.value : null;
for (const specifier of declaration.specifiers) {
exportDetails.push({
local: specifier.local.name,
exported: specifier.exported.name,
type: ExportClosureMapping.NAMED_CONSTANT,
range: declaration.range,
source,
});
}
return [];
return exportDetails;
}
function DefaultDeclaration(context, declaration) {
if (declaration.declaration) {
const range = declaration.range;
const source = null;
if (declaration.declaration.type === 'Identifier' && declaration.declaration.name) {
return [
{
local: declaration.declaration.name,
exported: declaration.declaration.name,
closureName: declaration.declaration.name,
type: ExportClosureMapping.NAMED_DEFAULT_FUNCTION,
range,
source,
},
];
}
function DefaultDeclaration(defaultDeclaration) {
const { declaration } = defaultDeclaration;
if (declaration.type === 'Identifier' && declaration.name) {
return [
{
local: declaration.name,
exported: declaration.name,
type: ExportClosureMapping.NAMED_DEFAULT_FUNCTION,
range: defaultDeclaration.range,
source: null,
},
];
}
return [];
}
function literalName(context, literal) {
// Literal can either be a SimpleLiteral, or RegExpLiteral
if ('regex' in literal) {
// This is a RegExpLiteral
context.warn('Rollup Plugin Closure Compiler found a Regex Literal Named Import. `import foo from "*/.hbs"`');
return '';
function NodeIsPreservedExport(node) {
return (node.type === 'ExpressionStatement' &&
node.expression.type === 'AssignmentExpression' &&
node.expression.left.type === 'MemberExpression' &&
node.expression.left.object.type === 'Identifier' &&
node.expression.left.object.name === 'window');
}
function PreservedExportName(node) {
const { property } = node;
if (property.type === 'Identifier') {
return property.name;
}
const literalValue = literal.value;
return typeof literalValue === 'string' ? literalValue : '';
if (property.type === 'Literal' && typeof property.value === 'string') {
return property.value;
}
return null;
}
function importLocalNames(context, declaration) {
const VALID_SPECIFIERS = [IMPORT_SPECIFIER, IMPORT_NAMESPACE_SPECIFIER, IMPORT_DEFAULT_SPECIFIER];
const returnableSpecifiers = [];
(declaration.specifiers || []).forEach(specifier => {
if (VALID_SPECIFIERS.includes(specifier.type)) {
returnableSpecifiers.push(specifier.local.name);
}
});
return returnableSpecifiers;
/**
* 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.
*/
function PreserveFunction(code, source, ancestor, exportDetails, exportInline) {
// Function Expressions can be inlined instead of preserved as variable references.
// window['foo'] = function(){}; => export function foo(){} / function foo(){}
const assignmentExpression = ancestor.expression;
const memberExpression = assignmentExpression.left;
const functionExpression = assignmentExpression.right;
const [memberExpressionObjectStart] = memberExpression.object.range;
const functionName = exportInline ? exportDetails.exported : exportDetails.local;
if (functionExpression.params.length > 0) {
const [paramsStart] = functionExpression.params[0].range;
// FunctionExpression has parameters.
source.overwrite(memberExpressionObjectStart, paramsStart, `${exportInline ? 'export ' : ''}function ${functionName}(`);
}
else {
const [bodyStart] = functionExpression.body.range;
source.overwrite(memberExpressionObjectStart, bodyStart, `${exportInline ? 'export ' : ''}function ${functionName}()`);
}
return !exportInline;
}
function PreserveIdentifier(code, source, ancestor, exportDetails, exportInline) {
const assignmentExpression = ancestor.expression;
const left = assignmentExpression.left;
const right = assignmentExpression.right;
const [ancestorStart, ancestorEnd] = ancestor.range;
const [rightStart, rightEnd] = right.range;
if (exportInline) {
source.overwrite(ancestorStart, ancestorEnd, `export var ${exportDetails.exported}=${code.substring(rightStart, rightEnd)};`);
}
else if (exportDetails.source === null && 'name' in right) {
// This is a locally defined identifier with a name we can use.
exportDetails.local = right.name;
source.remove(left.range[0], rightEnd + 1);
return true;
}
else {
// exportDetails.local =
source.overwrite(ancestorStart, ancestorEnd, `var ${exportDetails.local}=${code.substring(rightStart, rightEnd)};`);
}
return !exportInline;
}
function PreserveNamedConstant(code, source, ancestor, exportDetails, exportInline) {
const assignmentExpression = ancestor.expression;
switch (assignmentExpression.right.type) {
case 'FunctionExpression':
return PreserveFunction(code, source, ancestor, exportDetails, exportInline);
default:
return PreserveIdentifier(code, source, ancestor, exportDetails, exportInline);
}
}
/**
* 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.
*/
function PreserveDefault(code, source, ancestor, exportDetails, exportInline) {
const assignmentExpression = ancestor.expression;
const memberExpression = assignmentExpression.left;
const [memberExpressionStart, memberExpressionEnd] = memberExpression.range;
source.overwrite(memberExpressionStart, memberExpressionEnd + assignmentExpression.operator.length, 'export default ');
return false;
}
/**
* 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.
*/
async function writeTempFile(content, extension = '') {
const path$1 = path.join(os.tmpdir(), uuid.v4() + extension);
await fs.promises.mkdir(path.dirname(path$1), { recursive: true });
await fs.promises.writeFile(path$1, content, 'utf-8');
return path$1;
}
/**
* Copyright 2018 The AMP HTML Authors. All Rights Reserved.

@@ -296,5 +437,5 @@ *

*/
/* c8 ignore next 9 */
const logSource = (preamble, source, code) => {
};
/* c8 ignore next 16 */
async function logTransformChain(file, stage, messages) {
}

@@ -320,9 +461,6 @@ /**

* Checks if output format is ESM
* @param format
* @param outputOptions
* @return boolean
*/
const isESMFormat = (format) => {
// TODO: remove `| 'esm'` when rollup upgrades its typings
return format === 'esm' || format === 'es';
};
const isESMFormat = ({ format }) => format === 'esm' || format === 'es';
/**

@@ -332,3 +470,3 @@ * Throw Errors if compile options will result in unexpected behaviour.

*/
const validateCompileOptions = (compileOptions) => {
function validateCompileOptions(compileOptions) {
if ('warning_level' in compileOptions && compileOptions.warning_level === 'VERBOSE') {

@@ -338,7 +476,7 @@ if (!('language_out' in compileOptions)) {

}
else if ('language_out' in compileOptions && compileOptions.language_out === 'NO_TRANSPILE') {
if (compileOptions.language_out === 'NO_TRANSPILE') {
throw new Error(ERROR_WARNINGS_ENABLED_LANGUAGE_OUT_INVALID);
}
}
};
}
/**

@@ -351,3 +489,3 @@ * Generate default Closure Compiler CompileOptions an author can override if they wish.

*/
const defaults = (options, providedExterns, transformers) => {
const defaults = async (options, providedExterns, transformers) => {
// Defaults for Rollup Projects are slightly different than Closure Compiler defaults.

@@ -358,19 +496,16 @@ // - Users of Rollup tend to transpile their code before handing it to a minifier,

// so safely be more aggressive in minification.
const externs = transformers
? transformers
.map(transform => {
const extern = transform.extern(options);
return extern !== '' ? tempWrite.sync(extern) : false;
})
.filter(Boolean)
.concat(providedExterns)
: providedExterns.length > 0
? providedExterns
: '';
const transformerExterns = [];
for (const transform of transformers || []) {
const extern = transform.extern(options);
if (extern !== null) {
const writtenExtern = await writeTempFile(extern);
transformerExterns.push(writtenExtern);
}
}
return {
language_out: 'NO_TRANSPILE',
assume_function_wrapper: isESMFormat(options.format),
assume_function_wrapper: isESMFormat(options),
warning_level: 'QUIET',
module_resolution: 'NODE',
externs,
externs: transformerExterns.concat(providedExterns),
};

@@ -387,4 +522,4 @@ };

*/
function options (incomingCompileOptions, outputOptions, code, transforms) {
const mapFile = tempWrite.sync('');
async function options (incomingCompileOptions, outputOptions, code, transforms) {
const mapFile = await writeTempFile('');
const compileOptions = { ...incomingCompileOptions };

@@ -408,5 +543,5 @@ let externs = [];

const options = {
...defaults(outputOptions, externs, transforms),
...(await defaults(outputOptions, externs, transforms)),
...compileOptions,
js: tempWrite.sync(code),
js: await writeTempFile(code),
create_source_map: mapFile,

@@ -436,8 +571,2 @@ };

*/`;
const CJS_EXTERN = `/**
* @typedef {{
* __esModule: boolean,
* }}
*/
var exports;`;
/**

@@ -464,4 +593,7 @@ * This Transform will apply only if the Rollup configuration is for 'esm' output.

this.currentSourceExportCount++;
this.originalExports.set(map.local, map);
}
this.originalExports.set(map.closureName, map);
else {
this.originalExports.set(map.exported, map);
}
});

@@ -485,6 +617,6 @@ }

ExportNamedDeclaration(node) {
storeExport(NamedDeclaration(context, node));
storeExport(NamedDeclaration(node));
},
ExportDefaultDeclaration(node) {
storeExport(DefaultDeclaration(context, node));
storeExport(DefaultDeclaration(node));
},

@@ -497,14 +629,14 @@ ExportAllDeclaration(node) {

}
extern(options) {
let output = EXTERN_OVERVIEW;
if (options.format === 'cjs') {
output += CJS_EXTERN;
}
for (const key of this.originalExports.keys()) {
const value = this.originalExports.get(key);
if (value.source !== null) {
output += `function ${value.closureName}(){};\n`;
extern() {
if (Array.from(this.originalExports.keys()).length > 0) {
let output = EXTERN_OVERVIEW;
for (const key of this.originalExports.keys()) {
const value = this.originalExports.get(key);
if (value.source !== null) {
output += `function ${value.exported}(){};\n`;
}
}
return output;
}
return output;
return null;
}

@@ -520,29 +652,26 @@ /**

async preCompilation(code) {
if (this.outputOptions === null) {
this.context.warn('Rollup Plugin Closure Compiler, OutputOptions not known before Closure Compiler invocation.');
}
else if (isESMFormat(this.outputOptions.format)) {
await this.deriveExports(code);
const source = new MagicString(code);
for (const key of this.originalExports.keys()) {
const value = this.originalExports.get(key);
// Remove export statements before Closure Compiler sees the code
// This prevents CC from transpiling `export` statements when the language_out is set to a value
// where exports were not part of the language.
source.remove(...value.range);
// Window scoped references for each key are required to ensure Closure Compilre retains the code.
if (value.source === null) {
source.append(`\nwindow['${value.closureName}'] = ${value.local};`);
}
else {
source.append(`\nwindow['${value.closureName}'] = ${value.exported};`);
}
}
if (!isESMFormat(this.outputOptions)) {
return {
code: source.toString(),
map: source.generateMap().mappings,
code,
};
}
await this.deriveExports(code);
const source = new MagicString(code);
for (const key of this.originalExports.keys()) {
const value = this.originalExports.get(key);
// Remove export statements before Closure Compiler sees the code
// This prevents CC from transpiling `export` statements when the language_out is set to a value
// where exports were not part of the language.
source.remove(...value.range);
// Window scoped references for each key are required to ensure Closure Compilre retains the code.
if (value.source === null) {
source.append(`\nwindow['${value.local}'] = ${value.local};`);
}
else {
source.append(`\nwindow['${value.exported}'] = ${value.exported};`);
}
}
return {
code,
code: source.toString(),
map: source.generateMap().mappings,
};

@@ -559,119 +688,67 @@ }

async postCompilation(code) {
if (this.outputOptions === null) {
this.context.warn('Rollup Plugin Closure Compiler, OutputOptions not known before Closure Compiler invocation.');
if (!isESMFormat(this.outputOptions)) {
return {
code,
};
}
else if (isESMFormat(this.outputOptions.format)) {
const source = new MagicString(code);
const program = parse(code);
let collectedExportsToAppend = new Map();
const { originalExports, currentSourceExportCount } = this;
source.trimEnd();
walk.ancestor(program, {
// We inserted window scoped assignments for all the export statements during `preCompilation`
// Now we need to find where Closure Compiler moved them, and restore the exports of their name.
// ASTExporer Link: https://astexplorer.net/#/gist/94f185d06a4105d64828f1b8480bddc8/0fc5885ae5343f964d0cdd33c7d392a70cf5fcaf
Identifier(node, ancestors) {
if (node.name === 'window') {
ancestors.forEach((ancestor) => {
if (ancestor.type === 'ExpressionStatement' &&
ancestor.expression.type === 'AssignmentExpression' &&
ancestor.expression.left.type === 'MemberExpression' &&
ancestor.expression.left.object.type === 'Identifier' &&
ancestor.expression.left.object.name === 'window') {
const { property: leftProperty } = ancestor.expression.left;
let exportName = null;
if (leftProperty.type === 'Identifier') {
exportName = leftProperty.name;
const source = new MagicString(code);
const program = parse(code);
const { originalExports, currentSourceExportCount } = this;
let collectedExportsToAppend = new Map();
source.trimEnd();
walk.ancestor(program, {
// We inserted window scoped assignments for all the export statements during `preCompilation`
// Now we need to find where Closure Compiler moved them, and restore the exports of their name.
// ASTExporer Link: https://astexplorer.net/#/gist/94f185d06a4105d64828f1b8480bddc8/0fc5885ae5343f964d0cdd33c7d392a70cf5fcaf
Identifier(node, ancestors) {
if (node.name !== 'window') {
return;
}
for (const ancestor of ancestors) {
if (!NodeIsPreservedExport(ancestor)) {
continue;
}
// Can cast these since they were validated with the `NodeIsPreservedExport` test.
const expression = ancestor.expression;
const left = expression.left;
const exportName = PreservedExportName(left);
if (exportName !== null && originalExports.get(exportName)) {
const exportDetails = originalExports.get(exportName);
const exportIsLocal = exportDetails.source === null;
const exportInline = exportIsLocal &&
currentSourceExportCount === 1 &&
exportDetails.local === exportDetails.exported;
switch (exportDetails.type) {
case ExportClosureMapping.NAMED_DEFAULT_FUNCTION:
case ExportClosureMapping.DEFAULT:
if (PreserveDefault(code, source, ancestor)) ;
break;
case ExportClosureMapping.NAMED_CONSTANT:
if (PreserveNamedConstant(code, source, ancestor, exportDetails, exportInline)) {
collectedExportsToAppend = ExportTransform.storeExportToAppend(collectedExportsToAppend, exportDetails);
}
else if (leftProperty.type === 'Literal' &&
typeof leftProperty.value === 'string') {
exportName = leftProperty.value;
}
if (exportName !== null && originalExports.get(exportName)) {
const exportDetails = originalExports.get(exportName);
switch (exportDetails.type) {
case ExportClosureMapping.NAMED_DEFAULT_FUNCTION:
case ExportClosureMapping.DEFAULT:
if (ancestor.expression.left.range) {
source.overwrite(ancestor.expression.left.range[0], ancestor.expression.left.range[1] + ancestor.expression.operator.length, 'export default ');
}
break;
case ExportClosureMapping.NAMED_CONSTANT:
const exportFromCurrentSource = exportDetails.source === null;
const inlineExport = exportFromCurrentSource && currentSourceExportCount === 1;
let exportCollected = false;
if (exportFromCurrentSource) {
const { object: leftObject } = ancestor.expression.left;
if (leftObject.range) {
const { left, right } = ancestor.expression;
switch (right.type) {
case 'FunctionExpression':
// Function Expressions can be inlined instead of preserved as variable references.
// window['foo'] = function(){}; => export function foo(){} / function foo(){}
if (right.params.length > 0) {
// FunctionExpression has parameters.
source.overwrite(leftObject.range[0], right.params[0].range[0], `${inlineExport ? 'export ' : ''}function ${exportDetails.exported}(`);
}
else {
source.overwrite(leftObject.range[0], right.body.range[0], `${inlineExport ? 'export ' : ''}function ${exportDetails.exported}()`);
}
break;
case 'Identifier':
if (left.property.type === 'Identifier') {
// Identifiers are present when a complex object (class) has been saved as an export.
// In this case we currently opt out of inline exporting, since the identifier
// is a mangled name for the export.
exportDetails.local = right.name;
exportDetails.closureName = left.property.name;
source.remove(ancestor.expression.left.range[0], ancestor.expression.right.range[1] + 1);
// Since we're manually mapping the name back from the changes done by Closure
// Ensure the export isn't stored for insertion here and later on.
collectedExportsToAppend = ExportTransform.storeExportToAppend(collectedExportsToAppend, exportDetails);
exportCollected = true;
}
break;
default:
const statement = inlineExport ? 'export var ' : 'var ';
source.overwrite(leftObject.range[0], leftObject.range[1] + 1, statement);
break;
}
}
if (exportDetails.local !== exportDetails.exported) {
exportDetails.local = exportDetails.exported;
exportDetails.closureName = exportDetails.local;
}
}
else if (ancestor.expression.left.range &&
ancestor.expression.right.range) {
source.remove(ancestor.expression.left.range[0], ancestor.expression.right.range[1] + 1);
}
if (!inlineExport && !exportCollected) {
collectedExportsToAppend = ExportTransform.storeExportToAppend(collectedExportsToAppend, exportDetails);
}
break;
}
}
}
});
break;
}
if (!exportIsLocal) {
source.remove(left.range[0], expression.right.range[1] + 1);
}
}
},
});
for (const exportSource of collectedExportsToAppend.keys()) {
const toAppend = collectedExportsToAppend.get(exportSource);
if (toAppend && toAppend.length > 0) {
if (exportSource === null) {
source.append(`export{${toAppend.join(',')}}`);
}
else {
source.prepend(`export{${toAppend.join(',')}}from'${exportSource}';`);
}
}
},
});
for (const exportSource of collectedExportsToAppend.keys()) {
const toAppend = collectedExportsToAppend.get(exportSource);
if (toAppend && toAppend.length > 0) {
const names = toAppend.join(',');
if (exportSource === null) {
source.append(`export{${names}}`);
}
else {
source.prepend(`export{${names}}from'${exportSource}';`);
}
}
return {
code: source.toString(),
map: source.generateMap().mappings,
};
}
return {
code,
code: source.toString(),
map: source.generateMap().mappings,
};

@@ -682,2 +759,76 @@ }

/**
* 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.
*/
function literalName(literal) {
return literal.value;
}
/**
* 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.
*/
function Specifiers(specifiers) {
const returnable = {
default: null,
specific: [],
local: [],
};
for (const specifier of specifiers) {
returnable.local.push(specifier.local.name);
switch (specifier.type) {
case IMPORT_SPECIFIER:
case IMPORT_NAMESPACE_SPECIFIER:
const { name: local } = specifier.local;
const { name: imported } = specifier.imported;
if (local === imported) {
returnable.specific.push(local);
}
else {
returnable.specific.push(`${imported} as ${local}`);
}
break;
case IMPORT_DEFAULT_SPECIFIER:
returnable.default = specifier.local.name;
break;
}
}
return returnable;
}
function FormatSpecifiers(specifiers, name) {
let formatted = 'import ';
let values = [];
if (specifiers.default !== null) {
values.push(specifiers.default);
}
if (specifiers.specific.length > 0) {
values.push(`{${specifiers.specific.join(',')}}`);
}
formatted += `${values.join(',')} from '${name}';`;
return formatted;
}
/**
* Copyright 2018 The AMP HTML Authors. All Rights Reserved.

@@ -699,3 +850,3 @@ *

const DYNAMIC_IMPORT_REPLACEMENT = `import_${new Date().getMilliseconds()}`;
const HEADER$1 = `/**
const HEADER$2 = `/**
* @fileoverview Externs built via derived configuration from Rollup or input code.

@@ -720,7 +871,7 @@ * This extern contains the external import names, to prevent compilation failures.

extern() {
let extern = HEADER$1;
let extern = HEADER$2;
if (this.importedExternalsLocalNames.length > 0) {
this.importedExternalsLocalNames.forEach(name => {
for (const name of this.importedExternalsLocalNames) {
extern += `function ${name}(){};\n`;
});
}
}

@@ -736,3 +887,3 @@ if (this.dynamicImportPresent) {

}
return extern;
return extern === HEADER$2 ? null : extern;
}

@@ -752,25 +903,9 @@ /**

walk.simple(program, {
async ImportDeclaration(node) {
const name = literalName(self.context, node.source);
ImportDeclaration(node) {
const name = literalName(node.source);
const range = node.range;
let defaultSpecifier = null;
const specificSpecifiers = [];
for (const specifier of node.specifiers) {
switch (specifier.type) {
case IMPORT_SPECIFIER:
case IMPORT_NAMESPACE_SPECIFIER:
const { name: local } = specifier.local;
const { name: imported } = specifier.imported;
specificSpecifiers.push(local === imported ? local : `${imported} as ${local}`);
break;
case IMPORT_DEFAULT_SPECIFIER:
defaultSpecifier = specifier.local.name;
break;
}
}
self.importedExternalsSyntax[name] = `import ${defaultSpecifier !== null
? `${defaultSpecifier}${specificSpecifiers.length > 0 ? ',' : ''}`
: ''}${specificSpecifiers.length > 0 ? `{${specificSpecifiers.join(',')}}` : ''} from '${name}';`;
const specifiers = Specifiers(node.specifiers);
self.importedExternalsSyntax[name] = FormatSpecifiers(specifiers, name);
self.importedExternalsLocalNames.push(...specifiers.local);
source.remove(...range);
self.importedExternalsLocalNames = self.importedExternalsLocalNames.concat(importLocalNames(self.context, node));
},

@@ -798,3 +933,5 @@ Import(node) {

const program = parse(code);
Object.values(this.importedExternalsSyntax).forEach(importedExternalSyntax => source.prepend(importedExternalSyntax));
for (const importedExternalSyntax of Object.values(this.importedExternalsSyntax)) {
source.prepend(importedExternalSyntax);
}
walk.simple(program, {

@@ -842,7 +979,4 @@ Identifier(node) {

async postCompilation(code) {
if (this.outputOptions === null) {
this.context.warn('Rollup Plugin Closure Compiler, OutputOptions not known before Closure Compiler invocation.');
}
else if (isESMFormat(this.outputOptions.format) ||
(this.outputOptions.file && path.extname(this.outputOptions.file) === '.mjs')) {
const { file } = this.outputOptions;
if (isESMFormat(this.outputOptions) || (file && path.extname(file) === '.mjs')) {
const source = new MagicString(code);

@@ -852,6 +986,6 @@ const program = parse(code);

ExpressionStatement(node) {
if (node.expression.type === 'Literal' &&
node.expression.value === 'use strict' &&
node.range) {
source.remove(node.range[0], node.range[1]);
const { type, value } = node.expression;
const range = node.range;
if (type === 'Literal' && value === 'use strict') {
source.remove(...range);
}

@@ -902,4 +1036,5 @@ },

VariableDeclaration(node) {
if (node.kind === 'const' && node.range) {
source.overwrite(node.range[0], node.range[1], code.substring(node.range[0], node.range[1]).replace('const ', 'let '));
const [start, end] = node.range;
if (node.kind === 'const') {
source.overwrite(start, end, code.substring(start, end).replace('const', 'let'));
}

@@ -940,2 +1075,3 @@ },

new IifeTransform(context, options),
new CJSTransform(context, options),
new LiteralComputedKeys(context, options),

@@ -954,3 +1090,7 @@ new StrictTransform(context, options),

*/
async function preCompilation(code, outputOptions, transforms) {
async function preCompilation(code, outputOptions, chunk, transforms) {
// Each transform has a 'preCompilation' step that must complete before passing
// the resulting code to Closure Compiler.
const log = [];
log.push(['before', code]);
for (const transform of transforms) {

@@ -960,6 +1100,8 @@ transform.outputOptions = outputOptions;

if (result && result.code) {
logSource(`after ${transform.name} preCompilation`, result && result.code);
log.push([transform.name, code]);
code = result.code;
}
}
log.push(['after', code]);
await logTransformChain(chunk.fileName);
return code;

@@ -973,10 +1115,22 @@ }

*/
async function postCompilation(code, transforms) {
for (const transform of transforms) {
const result = await transform.postCompilation(code);
if (result && result.code) {
logSource(`after ${transform.name} postCompilation`, result && result.code);
code = result.code;
async function postCompilation(code, chunk, transforms) {
// Following successful Closure Compiler compilation, each transform needs an opportunity
// to clean up work is performed in preCompilation via postCompilation.
const log = [];
try {
log.push(['before', code]);
for (const transform of transforms) {
const result = await transform.postCompilation(code);
if (result && result.code) {
log.push([transform.name, result.code]);
code = result.code;
}
}
log.push(['after', code]);
await logTransformChain(chunk.fileName, 'PostCompilation', log);
}
catch (e) {
await logTransformChain(chunk.fileName);
throw e;
}
return code;

@@ -1045,3 +1199,3 @@ }

*/
function compiler (compileOptions, transforms) {
function compiler (compileOptions, chunk, transforms) {
return new Promise((resolve, reject) => {

@@ -1067,3 +1221,3 @@ const [config, platform] = filterContent(compileOptions);

else {
resolve(await postCompilation(code, transforms));
resolve(await postCompilation(code, chunk, transforms));
}

@@ -1097,8 +1251,8 @@ });

*/
const renderChunk = async (transforms, requestedCompileOptions = {}, sourceCode, outputOptions) => {
const code = await preCompilation(sourceCode, outputOptions, transforms);
const [compileOptions, mapFile] = options(requestedCompileOptions, outputOptions, code, transforms);
const renderChunk = async (transforms, requestedCompileOptions = {}, sourceCode, outputOptions, chunk) => {
const code = await preCompilation(sourceCode, outputOptions, chunk, transforms);
const [compileOptions, mapFile] = await options(requestedCompileOptions, outputOptions, code, transforms);
try {
return {
code: await compiler(compileOptions, transforms),
code: await compiler(compileOptions, chunk, transforms),
map: JSON.parse(await fs.promises.readFile(mapFile, 'utf8')),

@@ -1127,3 +1281,3 @@ };

const transforms = createTransforms(context, inputOptions);
const output = await renderChunk(transforms, requestedCompileOptions, code, outputOptions);
const output = await renderChunk(transforms, requestedCompileOptions, code, outputOptions, chunk);
return output || null;

@@ -1130,0 +1284,0 @@ },

{
"name": "@ampproject/rollup-plugin-closure-compiler",
"version": "0.18.1",
"version": "0.19.0",
"description": "Rollup + Google Closure Compiler",

@@ -23,3 +23,3 @@ "main": "dist/index.js",

"scripts": {
"pretest": "rimraf dist transpile && tsc -p tsconfig.test.json & wait",
"pretest": "tsc -p tsconfig.test.json",
"test": "ava",

@@ -31,3 +31,2 @@ "precoverage": "yarn pretest && c8 ava",

"postbuild": "rollup -c",
"lint": "tslint -c tslint.json -p tsconfig.json",
"release": "np",

@@ -43,5 +42,5 @@ "prepublishOnly": "npm-run-all build"

"acorn-walk": "7.0.0",
"google-closure-compiler": "20191111.0.0",
"magic-string": "0.25.4",
"temp-write": "4.0.0"
"google-closure-compiler": "20200101.0.0",
"magic-string": "0.25.5",
"uuid": "3.3.3"
},

@@ -51,4 +50,4 @@ "devDependencies": {

"@types/estree": "0.0.41",
"@types/node": "12.12.22",
"@types/temp-write": "3.3.0",
"@types/node": "12.12.24",
"@types/uuid": "3.4.6",
"ava": "2.4.0",

@@ -58,3 +57,3 @@ "builtins": "3.0.0",

"codecov": "3.6.1",
"husky": "3.1.0",
"husky": "4.0.1",
"lint-staged": "9.5.0",

@@ -65,5 +64,4 @@ "np": "5.2.1",

"rimraf": "3.0.0",
"rollup": "1.27.14",
"rollup": "1.29.0",
"sirv-cli": "0.4.5",
"tslint": "5.20.1",
"typescript": "3.7.4"

@@ -73,5 +71,8 @@ },

"*.ts": [
"yarn lint --fix",
"prettier --config .prettierrc --write",
"git add"
],
"*.test.js": [
"prettier --config .prettierrc --write",
"git add"
]

@@ -92,5 +93,5 @@ },

"volta": {
"node": "12.14.0",
"node": "12.14.1",
"yarn": "1.21.1"
}
}

Sorry, the diff of this file is not supported yet