Browse Source

Merge pull request #142 from Victorystick/import-of-unexported-fails

Made Scope.reference stricter. Helps to catch undefined/missing exports.
better-aggressive
Rich Harris 9 years ago
parent
commit
4401629d40
  1. 13
      src/Module.js
  2. 7
      src/Scope.js
  3. 10
      test/function/import-of-unexported-fails/_config.js
  4. 0
      test/function/import-of-unexported-fails/empty.js
  5. 3
      test/function/import-of-unexported-fails/main.js
  6. 16
      test/testScope.js

13
src/Module.js

@ -50,6 +50,18 @@ class Id {
}
}
class LateBoundIdPlaceholder {
constructor ( module, name ) {
this.module = module;
this.name = name;
this.placeholder = true;
}
mark () {
throw new Error(`The imported name "${this.name}" is never exported by "${this.module.id}".`);
}
}
export default class Module {
constructor ({ id, source, ast, bundle }) {
this.source = source;
@ -103,6 +115,7 @@ export default class Module {
}
// throw new Error( `The name "${name}" is never exported (from ${this.id})!` );
this.exports.define( name, new LateBoundIdPlaceholder( this, name ) );
return reference.call( this.exports, name );
};

7
src/Scope.js

@ -81,6 +81,7 @@ export default class Scope {
});
this.ids.filter( isntReference ).forEach( id => {
// TODO: can this be removed?
if ( typeof id === 'string' ) {
throw new Error( `Required name "${id}" is undefined!` );
}
@ -153,7 +154,11 @@ export default class Scope {
// Get a reference to the identifier `name` in this scope.
reference ( name ) {
return new Reference( this, this.index( name ) );
if ( !( name in this.names ) ) {
throw new Error( `Cannot reference undefined identifier "${name}"` );
}
return new Reference( this, this.names[ name ] );
}
// Return the used names of the scope.

10
test/function/import-of-unexported-fails/_config.js

@ -0,0 +1,10 @@
var assert = require( 'assert' );
module.exports = {
description: 'marking an imported, but unexported, identifier should throw',
error: function ( err ) {
assert.equal( err.message.slice( 0, 50 ), 'The imported name "default" is never exported by "' );
assert.equal( err.message.slice( -10 ), 'empty.js".' );
}
};

0
test/function/import-of-unexported-fails/empty.js

3
test/function/import-of-unexported-fails/main.js

@ -0,0 +1,3 @@
import a from './empty.js';
a();

16
test/testScope.js

@ -93,7 +93,7 @@ describe( 'Scope', function () {
});
});
it( 'dedupes-external-imports', function () {
it( 'cannot reference undefined names', function () {
var real = new Scope();
var external = real.virtual(),
@ -104,17 +104,11 @@ describe( 'Scope', function () {
locals.bind( 'Comp', external.reference( 'Component' ) );
exports.bind( 'default', locals.reference( 'Foo' ) );
try {
real.deconflict();
assert.ok( false, 'Scope.deconflict should throw with "Foo" undefined' );
} catch ( ignore ) {
// as expected
}
assert.throws( function () {
exports.bind( 'default', locals.reference( 'Foo' ) );
}, 'Cannot reference undefined identifier "Foo"' );
locals.define( 'Foo' );
real.deconflict();
exports.bind( 'default', locals.reference( 'Foo' ) );
});
});

Loading…
Cancel
Save