From 82b284de1d4b357f0c74d6b454442014fee230cc Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Sat, 7 Jan 2017 15:54:49 -0500 Subject: [PATCH] optimize ns["foo"] (#841) --- src/ast/nodes/MemberExpression.js | 22 ++++++++++++++----- .../_config.js | 3 +++ .../_expected/amd.js | 7 ++++++ .../_expected/cjs.js | 5 +++++ .../_expected/es.js | 3 +++ .../_expected/iife.js | 8 +++++++ .../_expected/umd.js | 11 ++++++++++ .../bar.js | 3 +++ .../foo.js | 3 +++ .../main.js | 3 +++ .../quux.js | 1 + 11 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 test/form/namespace-optimization-computed-string/_config.js create mode 100644 test/form/namespace-optimization-computed-string/_expected/amd.js create mode 100644 test/form/namespace-optimization-computed-string/_expected/cjs.js create mode 100644 test/form/namespace-optimization-computed-string/_expected/es.js create mode 100644 test/form/namespace-optimization-computed-string/_expected/iife.js create mode 100644 test/form/namespace-optimization-computed-string/_expected/umd.js create mode 100644 test/form/namespace-optimization-computed-string/bar.js create mode 100644 test/form/namespace-optimization-computed-string/foo.js create mode 100644 test/form/namespace-optimization-computed-string/main.js create mode 100644 test/form/namespace-optimization-computed-string/quux.js diff --git a/src/ast/nodes/MemberExpression.js b/src/ast/nodes/MemberExpression.js index d745d7d..9b2313d 100644 --- a/src/ast/nodes/MemberExpression.js +++ b/src/ast/nodes/MemberExpression.js @@ -1,14 +1,24 @@ -import isReference from 'is-reference'; import relativeId from '../../utils/relativeId.js'; import Node from '../Node.js'; import { UNKNOWN } from '../values.js'; +const validProp = /^[a-zA-Z_$][a-zA-Z_$0-9]*$/; + class Keypath { constructor ( node ) { this.parts = []; while ( node.type === 'MemberExpression' ) { - this.parts.unshift( node.property ); + const prop = node.property; + + if ( node.computed ) { + if ( prop.type !== 'Literal' || typeof prop.value !== 'string' || !validProp.test( prop.value ) ) { + this.computed = true; + return; + } + } + + this.parts.unshift( prop ); node = node.object; } @@ -21,21 +31,21 @@ export default class MemberExpression extends Node { // if this resolves to a namespaced declaration, prepare // to replace it // TODO this code is a bit inefficient - if ( isReference( this ) ) { // TODO optimise namespace access like `foo['bar']` as well - const keypath = new Keypath( this ); + const keypath = new Keypath( this ); + if ( !keypath.computed ) { let declaration = scope.findDeclaration( keypath.root.name ); while ( declaration.isNamespace && keypath.parts.length ) { const exporterId = declaration.module.id; const part = keypath.parts[0]; - declaration = declaration.module.traceExport( part.name ); + declaration = declaration.module.traceExport( part.name || part.value ); if ( !declaration ) { this.module.warn({ code: 'MISSING_EXPORT', - message: `'${part.name}' is not exported by '${relativeId( exporterId )}'`, + message: `'${part.name || part.value}' is not exported by '${relativeId( exporterId )}'`, url: `https://github.com/rollup/rollup/wiki/Troubleshooting#name-is-not-exported-by-module` }, part.start ); this.replacement = 'undefined'; diff --git a/test/form/namespace-optimization-computed-string/_config.js b/test/form/namespace-optimization-computed-string/_config.js new file mode 100644 index 0000000..1e58a85 --- /dev/null +++ b/test/form/namespace-optimization-computed-string/_config.js @@ -0,0 +1,3 @@ +module.exports = { + description: 'it does dynamic lookup optimization of internal namespaces for string-literal keys' +}; diff --git a/test/form/namespace-optimization-computed-string/_expected/amd.js b/test/form/namespace-optimization-computed-string/_expected/amd.js new file mode 100644 index 0000000..a244c47 --- /dev/null +++ b/test/form/namespace-optimization-computed-string/_expected/amd.js @@ -0,0 +1,7 @@ +define(function () { 'use strict'; + + function a () {} + + a(); + +}); diff --git a/test/form/namespace-optimization-computed-string/_expected/cjs.js b/test/form/namespace-optimization-computed-string/_expected/cjs.js new file mode 100644 index 0000000..b52a7e5 --- /dev/null +++ b/test/form/namespace-optimization-computed-string/_expected/cjs.js @@ -0,0 +1,5 @@ +'use strict'; + +function a () {} + +a(); diff --git a/test/form/namespace-optimization-computed-string/_expected/es.js b/test/form/namespace-optimization-computed-string/_expected/es.js new file mode 100644 index 0000000..8bee044 --- /dev/null +++ b/test/form/namespace-optimization-computed-string/_expected/es.js @@ -0,0 +1,3 @@ +function a () {} + +a(); diff --git a/test/form/namespace-optimization-computed-string/_expected/iife.js b/test/form/namespace-optimization-computed-string/_expected/iife.js new file mode 100644 index 0000000..206c237 --- /dev/null +++ b/test/form/namespace-optimization-computed-string/_expected/iife.js @@ -0,0 +1,8 @@ +(function () { + 'use strict'; + + function a () {} + + a(); + +}()); diff --git a/test/form/namespace-optimization-computed-string/_expected/umd.js b/test/form/namespace-optimization-computed-string/_expected/umd.js new file mode 100644 index 0000000..87757b5 --- /dev/null +++ b/test/form/namespace-optimization-computed-string/_expected/umd.js @@ -0,0 +1,11 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory() : + typeof define === 'function' && define.amd ? define(factory) : + (factory()); +}(this, (function () { 'use strict'; + + function a () {} + + a(); + +}))); diff --git a/test/form/namespace-optimization-computed-string/bar.js b/test/form/namespace-optimization-computed-string/bar.js new file mode 100644 index 0000000..9920490 --- /dev/null +++ b/test/form/namespace-optimization-computed-string/bar.js @@ -0,0 +1,3 @@ +import * as quux from './quux.js'; + +export { quux }; diff --git a/test/form/namespace-optimization-computed-string/foo.js b/test/form/namespace-optimization-computed-string/foo.js new file mode 100644 index 0000000..ec3731e --- /dev/null +++ b/test/form/namespace-optimization-computed-string/foo.js @@ -0,0 +1,3 @@ +import * as bar from './bar.js'; + +export { bar }; diff --git a/test/form/namespace-optimization-computed-string/main.js b/test/form/namespace-optimization-computed-string/main.js new file mode 100644 index 0000000..8dcfe71 --- /dev/null +++ b/test/form/namespace-optimization-computed-string/main.js @@ -0,0 +1,3 @@ +import * as foo from './foo.js'; + +foo['bar']['quux']['a'](); diff --git a/test/form/namespace-optimization-computed-string/quux.js b/test/form/namespace-optimization-computed-string/quux.js new file mode 100644 index 0000000..103a9f0 --- /dev/null +++ b/test/form/namespace-optimization-computed-string/quux.js @@ -0,0 +1 @@ +export function a () {}