From 9d91ecaa71bd0c36a51268579b13f10d9c0786b7 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Mon, 18 Jan 2016 13:08:25 -0500 Subject: [PATCH] error if namespace is called (#446) --- src/Declaration.js | 2 ++ src/utils/error.js | 9 +++++++++ src/utils/run.js | 16 +++++++++++++++- .../cannot-call-external-namespace/_config.js | 12 ++++++++++++ .../cannot-call-external-namespace/main.js | 2 ++ .../cannot-call-internal-namespace/_config.js | 12 ++++++++++++ .../cannot-call-internal-namespace/foo.js | 1 + .../cannot-call-internal-namespace/main.js | 2 ++ 8 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/utils/error.js create mode 100644 test/function/cannot-call-external-namespace/_config.js create mode 100644 test/function/cannot-call-external-namespace/main.js create mode 100644 test/function/cannot-call-internal-namespace/_config.js create mode 100644 test/function/cannot-call-internal-namespace/foo.js create mode 100644 test/function/cannot-call-internal-namespace/main.js diff --git a/src/Declaration.js b/src/Declaration.js index 831a966..2aca2a8 100644 --- a/src/Declaration.js +++ b/src/Declaration.js @@ -134,6 +134,7 @@ export class SyntheticDefaultDeclaration { export class SyntheticNamespaceDeclaration { constructor ( module ) { + this.isNamespace = true; this.module = module; this.name = null; @@ -221,6 +222,7 @@ export class ExternalDeclaration { this.module = module; this.name = name; this.isExternal = true; + this.isNamespace = name === '*'; } addAlias () { diff --git a/src/utils/error.js b/src/utils/error.js new file mode 100644 index 0000000..5c0a703 --- /dev/null +++ b/src/utils/error.js @@ -0,0 +1,9 @@ +export default function error ( props ) { + const err = new Error( props.message ); + + Object.keys( props ).forEach( key => { + err[ key ] = props[ key ]; + }); + + throw err; +} diff --git a/src/utils/run.js b/src/utils/run.js index bf35a73..4470305 100644 --- a/src/utils/run.js +++ b/src/utils/run.js @@ -3,6 +3,8 @@ import modifierNodes, { isModifierNode } from '../ast/modifierNodes.js'; import isReference from '../ast/isReference.js'; import flatten from '../ast/flatten'; import pureFunctions from './pureFunctions.js'; +import getLocation from './getLocation.js'; +import error from './error.js'; function call ( callee, scope, statement, strongDependencies ) { while ( callee.type === 'ParenthesizedExpression' ) callee = callee.expression; @@ -11,7 +13,19 @@ function call ( callee, scope, statement, strongDependencies ) { const declaration = scope.findDeclaration( callee.name ) || statement.module.trace( callee.name ); - if ( declaration ) return declaration.run( strongDependencies ); + if ( declaration ) { + if ( declaration.isNamespace ) { + error({ + message: `Cannot call a namespace ('${callee.name}')`, + file: statement.module.id, + pos: callee.start, + loc: getLocation( statement.module.code, callee.start ) + }); + } + + return declaration.run( strongDependencies ); + } + return !pureFunctions[ callee.name ]; } diff --git a/test/function/cannot-call-external-namespace/_config.js b/test/function/cannot-call-external-namespace/_config.js new file mode 100644 index 0000000..fa1e422 --- /dev/null +++ b/test/function/cannot-call-external-namespace/_config.js @@ -0,0 +1,12 @@ +var path = require( 'path' ); +var assert = require( 'assert' ); + +module.exports = { + description: 'errors if code calls an external namespace', + error: function ( err ) { + assert.equal( err.message, 'Cannot call a namespace (\'foo\')' ); + assert.equal( err.file, path.resolve( __dirname, 'main.js' ) ); + assert.equal( err.pos, 28 ); + assert.deepEqual( err.loc, { line: 2, column: 0 }); + } +}; diff --git a/test/function/cannot-call-external-namespace/main.js b/test/function/cannot-call-external-namespace/main.js new file mode 100644 index 0000000..c1ad7c6 --- /dev/null +++ b/test/function/cannot-call-external-namespace/main.js @@ -0,0 +1,2 @@ +import * as foo from 'foo'; +foo(); diff --git a/test/function/cannot-call-internal-namespace/_config.js b/test/function/cannot-call-internal-namespace/_config.js new file mode 100644 index 0000000..cf58000 --- /dev/null +++ b/test/function/cannot-call-internal-namespace/_config.js @@ -0,0 +1,12 @@ +var path = require( 'path' ); +var assert = require( 'assert' ); + +module.exports = { + description: 'errors if code calls an internal namespace', + error: function ( err ) { + assert.equal( err.message, 'Cannot call a namespace (\'foo\')' ); + assert.equal( err.file, path.resolve( __dirname, 'main.js' ) ); + assert.equal( err.pos, 33 ); + assert.deepEqual( err.loc, { line: 2, column: 0 }); + } +}; diff --git a/test/function/cannot-call-internal-namespace/foo.js b/test/function/cannot-call-internal-namespace/foo.js new file mode 100644 index 0000000..cc798ff --- /dev/null +++ b/test/function/cannot-call-internal-namespace/foo.js @@ -0,0 +1 @@ +export const a = 1; diff --git a/test/function/cannot-call-internal-namespace/main.js b/test/function/cannot-call-internal-namespace/main.js new file mode 100644 index 0000000..74f0acb --- /dev/null +++ b/test/function/cannot-call-internal-namespace/main.js @@ -0,0 +1,2 @@ +import * as foo from './foo.js'; +foo();