diff --git a/src/Bundle.js b/src/Bundle.js index 9332b83..f2f0dd2 100644 --- a/src/Bundle.js +++ b/src/Bundle.js @@ -188,7 +188,10 @@ export default class Bundle { `'${unused[0]}' is` : `${unused.slice( 0, -1 ).map( name => `'${name}'` ).join( ', ' )} and '${unused.pop()}' are`; - this.onwarn( `${names} imported from external module '${module.id}' but never used` ); + this.warn({ + code: 'UNUSED_EXTERNAL_IMPORT', + message: `${names} imported from external module '${module.id}' but never used` + }); }); this.orderedModules = this.sort(); @@ -309,7 +312,10 @@ export default class Bundle { keys( exportAllModule.exportsAll ).forEach( name => { if ( name in module.exportsAll ) { - this.onwarn( `Conflicting namespaces: ${module.id} re-exports '${name}' from both ${module.exportsAll[ name ]} (will be ignored) and ${exportAllModule.exportsAll[ name ]}.` ); + this.warn({ + code: 'NAMESPACE_CONFLICT', + message: `Conflicting namespaces: ${relativeId( module.id )} re-exports '${name}' from both ${relativeId( module.exportsAll[ name ] )} (will be ignored) and ${relativeId( exportAllModule.exportsAll[ name ] )}` + }); } module.exportsAll[ name ] = exportAllModule.exportsAll[ name ]; }); @@ -333,7 +339,11 @@ export default class Bundle { if ( !resolvedId && !isExternal ) { if ( isRelative( source ) ) throw new Error( `Could not resolve '${source}' from ${module.id}` ); - this.onwarn( `'${source}' is imported by ${relativeId( module.id )}, but could not be resolved – treating it as an external dependency. For help see https://github.com/rollup/rollup/wiki/Troubleshooting#treating-module-as-external-dependency` ); + this.warn({ + code: 'UNRESOLVED_IMPORT', + message: `'${source}' is imported by ${relativeId( module.id )}, but could not be resolved – treating it as an external dependency`, + url: 'https://github.com/rollup/rollup/wiki/Troubleshooting#treating-module-as-external-dependency' + }); isExternal = true; } @@ -380,7 +390,11 @@ export default class Bundle { render ( options = {} ) { if ( options.format === 'es6' ) { - this.onwarn( 'The es6 format is deprecated – use `es` instead' ); + this.warn({ + code: 'DEPRECATED_ES6', + message: 'The es6 format is deprecated – use `es` instead' + }); + options.format = 'es'; } @@ -404,7 +418,10 @@ export default class Bundle { }); if ( !magicString.toString().trim() && this.entryModule.getExports().length === 0 ) { - this.onwarn( 'Generated an empty bundle' ); + this.warn({ + code: 'EMPTY_BUNDLE', + message: 'Generated an empty bundle' + }); } timeEnd( 'render modules' ); @@ -470,7 +487,7 @@ export default class Bundle { if ( typeof map.mappings === 'string' ) { map.mappings = decode( map.mappings ); } - map = collapseSourcemaps( file, map, usedModules, bundleSourcemapChain, this.onwarn ); + map = collapseSourcemaps( this, file, map, usedModules, bundleSourcemapChain ); } else { map = magicString.generateMap({ file, includeContent: true }); } @@ -535,6 +552,7 @@ export default class Bundle { for ( i += 1; i < ordered.length; i += 1 ) { const b = ordered[i]; + // TODO reinstate this! it no longer works if ( stronglyDependsOn[ a.id ][ b.id ] ) { // somewhere, there is a module that imports b before a. Because // b imports a, a is placed before b. We need to find the module diff --git a/src/Module.js b/src/Module.js index 97f6cca..81926c3 100644 --- a/src/Module.js +++ b/src/Module.js @@ -180,7 +180,12 @@ export default class Module { this.exports[ exportedName ] = { localName }; }); } else { - this.bundle.onwarn( `Module ${this.id} has an empty export declaration` ); + // TODO is this really necessary? `export {}` is valid JS, and + // might be used as a hint that this is indeed a module + this.warn({ + code: 'EMPTY_EXPORT', + message: `Empty export declaration` + }, node.start ); } } } @@ -408,17 +413,12 @@ export default class Module { } warn ( warning, pos ) { - if ( pos ) { + if ( pos !== undefined ) { warning.pos = pos; const { line, column } = locate( this.code, pos, { offsetLine: 1 }); // TODO trace sourcemaps - warning.loc = { - file: this.id, - line: line + 1, - column - }; - + warning.loc = { file: this.id, line, column }; warning.frame = getCodeFrame( this.code, line, column ); } diff --git a/src/ast/nodes/ExportDefaultDeclaration.js b/src/ast/nodes/ExportDefaultDeclaration.js index 743287e..208120f 100644 --- a/src/ast/nodes/ExportDefaultDeclaration.js +++ b/src/ast/nodes/ExportDefaultDeclaration.js @@ -74,8 +74,11 @@ export default class ExportDefaultDeclaration extends Node { const newlineSeparated = /\n/.test( code.original.slice( start, end ) ); if ( newlineSeparated ) { - const { line, column } = locate( this.module.code, this.declaration.start, { offsetLine: 1 }); - this.module.bundle.onwarn( `${relativeId( this.module.id )} (${line}:${column}) Ambiguous default export (is a call expression, but looks like a function declaration). See https://github.com/rollup/rollup/wiki/Troubleshooting#ambiguous-default-export` ); + this.module.warn({ + code: 'AMBIGUOUS_DEFAULT_EXPORT', + message: `Ambiguous default export (is a call expression, but looks like a function declaration)`, + url: 'https://github.com/rollup/rollup/wiki/Troubleshooting#ambiguous-default-export' + }, this.declaration.start ); } } } diff --git a/src/ast/nodes/MemberExpression.js b/src/ast/nodes/MemberExpression.js index 4da3031..d745d7d 100644 --- a/src/ast/nodes/MemberExpression.js +++ b/src/ast/nodes/MemberExpression.js @@ -1,5 +1,4 @@ import isReference from 'is-reference'; -import { locate } from 'locate-character'; import relativeId from '../../utils/relativeId.js'; import Node from '../Node.js'; import { UNKNOWN } from '../values.js'; @@ -34,8 +33,11 @@ export default class MemberExpression extends Node { declaration = declaration.module.traceExport( part.name ); if ( !declaration ) { - const { line, column } = locate( this.module.code, this.start, { offsetLine: 1 }); - this.module.bundle.onwarn( `${relativeId( this.module.id )} (${line}:${column}) '${part.name}' is not exported by '${relativeId( exporterId )}'. See https://github.com/rollup/rollup/wiki/Troubleshooting#name-is-not-exported-by-module` ); + this.module.warn({ + code: 'MISSING_EXPORT', + message: `'${part.name}' 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'; return; } diff --git a/src/ast/nodes/ThisExpression.js b/src/ast/nodes/ThisExpression.js index 666be58..2429c65 100644 --- a/src/ast/nodes/ThisExpression.js +++ b/src/ast/nodes/ThisExpression.js @@ -1,8 +1,4 @@ import Node from '../Node.js'; -import { locate } from 'locate-character'; -import relativeId from '../../utils/relativeId.js'; - -const warning = `The 'this' keyword is equivalent to 'undefined' at the top level of an ES module, and has been rewritten. See https://github.com/rollup/rollup/wiki/Troubleshooting#this-is-undefined for more information`; export default class ThisExpression extends Node { initialise ( scope ) { @@ -11,9 +7,11 @@ export default class ThisExpression extends Node { if ( lexicalBoundary.isModuleScope ) { this.alias = this.module.context; if ( this.alias === 'undefined' ) { - const { line, column } = locate( this.module.code, this.start, { offsetLine: 1 }); - const detail = `${relativeId( this.module.id )} (${line}:${column + 1})`; // use one-based column number convention - this.module.bundle.onwarn( `${detail} ${warning}` ); + this.module.warn({ + code: 'THIS_IS_UNDEFINED', + message: `The 'this' keyword is equivalent to 'undefined' at the top level of an ES module, and has been rewritten`, + url: `https://github.com/rollup/rollup/wiki/Troubleshooting#this-is-undefined` + }, this.start ); } } } diff --git a/src/ast/scopes/ModuleScope.js b/src/ast/scopes/ModuleScope.js index 4c8804c..f0f5f7a 100644 --- a/src/ast/scopes/ModuleScope.js +++ b/src/ast/scopes/ModuleScope.js @@ -1,4 +1,5 @@ import { forOwn } from '../../utils/object.js'; +import relativeId from '../../utils/relativeId.js'; import Scope from './Scope.js'; export default class ModuleScope extends Scope { @@ -26,7 +27,10 @@ export default class ModuleScope extends Scope { if ( specifier.name !== '*' ) { const declaration = specifier.module.traceExport( specifier.name ); if ( !declaration ) { - this.module.bundle.onwarn( `Non-existent export '${specifier.name}' is imported from ${specifier.module.id} by ${this.module.id}` ); + this.module.warn({ + code: 'NON_EXISTENT_EXPORT', + message: `Non-existent export '${specifier.name}' is imported from ${relativeId( specifier.module.id )}` + }, specifier.specifier.start ); return; } diff --git a/src/finalisers/iife.js b/src/finalisers/iife.js index f6d702e..2d6121e 100644 --- a/src/finalisers/iife.js +++ b/src/finalisers/iife.js @@ -25,7 +25,7 @@ function setupNamespace ( keypath ) { } export default function iife ( bundle, magicString, { exportMode, indentString, intro, outro }, options ) { - const globalNameMaker = getGlobalNameMaker( options.globals || blank(), bundle.onwarn ); + const globalNameMaker = getGlobalNameMaker( options.globals || blank(), bundle ); const name = options.moduleName; const isNamespaced = name && ~name.indexOf( '.' ); diff --git a/src/finalisers/shared/getGlobalNameMaker.js b/src/finalisers/shared/getGlobalNameMaker.js index 676b416..7a1d622 100644 --- a/src/finalisers/shared/getGlobalNameMaker.js +++ b/src/finalisers/shared/getGlobalNameMaker.js @@ -1,11 +1,15 @@ -export default function getGlobalNameMaker ( globals, onwarn ) { +export default function getGlobalNameMaker ( globals, bundle ) { const fn = typeof globals === 'function' ? globals : id => globals[ id ]; return function ( module ) { const name = fn( module.id ); if ( name ) return name; - onwarn( `No name was provided for external module '${module.id}' in options.globals – guessing '${module.name}'` ); + bundle.warn({ + code: 'MISSING_GLOBAL_NAME', + message: `No name was provided for external module '${module.id}' in options.globals – guessing '${module.name}'` + }); + return module.name; }; } diff --git a/src/finalisers/shared/warnOnBuiltins.js b/src/finalisers/shared/warnOnBuiltins.js index e5ac1ba..c4d63f6 100644 --- a/src/finalisers/shared/warnOnBuiltins.js +++ b/src/finalisers/shared/warnOnBuiltins.js @@ -35,5 +35,8 @@ export default function warnOnBuiltins ( bundle ) { `module ('${externalBuiltins[0]}')` : `modules (${externalBuiltins.slice( 0, -1 ).map( name => `'${name}'` ).join( ', ' )} and '${externalBuiltins.pop()}')`; - bundle.onwarn( `Creating a browser bundle that depends on Node.js built-in ${detail}. You might need to include https://www.npmjs.com/package/rollup-plugin-node-builtins` ); + bundle.warn({ + code: 'MISSING_NODE_BUILTINS', + message: `Creating a browser bundle that depends on Node.js built-in ${detail}. You might need to include https://www.npmjs.com/package/rollup-plugin-node-builtins` + }); } diff --git a/src/finalisers/umd.js b/src/finalisers/umd.js index c176242..655c77a 100644 --- a/src/finalisers/umd.js +++ b/src/finalisers/umd.js @@ -33,7 +33,7 @@ export default function umd ( bundle, magicString, { exportMode, indentString, i warnOnBuiltins( bundle ); - const globalNameMaker = getGlobalNameMaker( options.globals || blank(), bundle.onwarn ); + const globalNameMaker = getGlobalNameMaker( options.globals || blank(), bundle ); const amdDeps = bundle.externalModules.map( quotePath ); const cjsDeps = bundle.externalModules.map( req ); diff --git a/src/utils/collapseSourcemaps.js b/src/utils/collapseSourcemaps.js index 7a504ba..122a148 100644 --- a/src/utils/collapseSourcemaps.js +++ b/src/utils/collapseSourcemaps.js @@ -98,7 +98,7 @@ class Link { } } -export default function collapseSourcemaps ( file, map, modules, bundleSourcemapChain, onwarn ) { +export default function collapseSourcemaps ( bundle, file, map, modules, bundleSourcemapChain ) { const moduleSources = modules.filter( module => !module.excludeFromSourcemap ).map( module => { let sourceMapChain = module.sourceMapChain; @@ -127,7 +127,11 @@ export default function collapseSourcemaps ( file, map, modules, bundleSourcemap sourceMapChain.forEach( map => { if ( map.missing ) { - onwarn( `Sourcemap is likely to be incorrect: a plugin${map.plugin ? ` ('${map.plugin}')` : ``} was used to transform files, but didn't generate a sourcemap for the transformation. Consult https://github.com/rollup/rollup/wiki/Troubleshooting and the plugin documentation for more information` ); + bundle.warn({ + code: 'SOURCEMAP_BROKEN', + message: `Sourcemap is likely to be incorrect: a plugin${map.plugin ? ` ('${map.plugin}')` : ``} was used to transform files, but didn't generate a sourcemap for the transformation. Consult the plugin documentation for help`, + url: `https://github.com/rollup/rollup/wiki/Troubleshooting#sourcemap-is-likely-to-be-incorrect` + }); map = { names: [], diff --git a/src/utils/getExportMode.js b/src/utils/getExportMode.js index a3d00a0..d525550 100644 --- a/src/utils/getExportMode.js +++ b/src/utils/getExportMode.js @@ -24,7 +24,11 @@ export default function getExportMode ( bundle, {exports: exportMode, moduleName exportMode = 'default'; } else { if ( bundle.entryModule.exports.default && format !== 'es') { - bundle.onwarn( `Using named and default exports together. Consumers of your bundle will have to use ${moduleName || 'bundle'}['default'] to access the default export, which may not be what you want. Use \`exports: 'named'\` to disable this warning. See https://github.com/rollup/rollup/wiki/JavaScript-API#exports for more information` ); + bundle.warn({ + code: 'MIXED_EXPORTS', + message: `Using named and default exports together. Consumers of your bundle will have to use ${moduleName || 'bundle'}['default'] to access the default export, which may not be what you want. Use \`exports: 'named'\` to disable this warning`, + url: `https://github.com/rollup/rollup/wiki/JavaScript-API#exports` + }); } exportMode = 'named'; } diff --git a/test/function/assign-namespace-to-var/_config.js b/test/function/assign-namespace-to-var/_config.js index 2eb7e9c..a8c94ea 100644 --- a/test/function/assign-namespace-to-var/_config.js +++ b/test/function/assign-namespace-to-var/_config.js @@ -2,9 +2,10 @@ const assert = require( 'assert' ); module.exports = { description: 'allows a namespace to be assigned to a variable', - warnings: warnings => { - assert.deepEqual( warnings, [ - 'Generated an empty bundle' - ]); - } + warnings: [ + { + code: 'EMPTY_BUNDLE', + message: 'Generated an empty bundle' + } + ] }; diff --git a/test/function/custom-path-resolver-async/_config.js b/test/function/custom-path-resolver-async/_config.js index 83a10c1..3924db7 100644 --- a/test/function/custom-path-resolver-async/_config.js +++ b/test/function/custom-path-resolver-async/_config.js @@ -21,11 +21,13 @@ module.exports = { } }] }, - warnings: function ( warnings ) { - assert.deepEqual( warnings, [ - `'path' is imported by main.js, but could not be resolved – treating it as an external dependency. For help see https://github.com/rollup/rollup/wiki/Troubleshooting#treating-module-as-external-dependency` - ]); - }, + warnings: [ + { + code: 'UNRESOLVED_IMPORT', + message: `'path' is imported by main.js, but could not be resolved – treating it as an external dependency`, + url: `https://github.com/rollup/rollup/wiki/Troubleshooting#treating-module-as-external-dependency` + } + ], exports: function ( exports ) { assert.strictEqual( exports.path, require( 'path' ) ); } diff --git a/test/function/custom-path-resolver-sync/_config.js b/test/function/custom-path-resolver-sync/_config.js index 074f671..f32cb9a 100644 --- a/test/function/custom-path-resolver-sync/_config.js +++ b/test/function/custom-path-resolver-sync/_config.js @@ -13,11 +13,13 @@ module.exports = { } }] }, - warnings: function ( warnings ) { - assert.deepEqual( warnings, [ - `'path' is imported by main.js, but could not be resolved – treating it as an external dependency. For help see https://github.com/rollup/rollup/wiki/Troubleshooting#treating-module-as-external-dependency` - ]); - }, + warnings: [ + { + code: 'UNRESOLVED_IMPORT', + message: `'path' is imported by main.js, but could not be resolved – treating it as an external dependency`, + url: `https://github.com/rollup/rollup/wiki/Troubleshooting#treating-module-as-external-dependency` + } + ], exports: function ( exports ) { assert.strictEqual( exports.path, require( 'path' ) ); } diff --git a/test/function/does-not-hang-on-missing-module/_config.js b/test/function/does-not-hang-on-missing-module/_config.js index 901bfae..aeb5386 100644 --- a/test/function/does-not-hang-on-missing-module/_config.js +++ b/test/function/does-not-hang-on-missing-module/_config.js @@ -2,11 +2,13 @@ var assert = require( 'assert' ); module.exports = { description: 'does not hang on missing module (#53)', - warnings: warnings => { - assert.deepEqual( warnings, [ - `'unlessYouCreatedThisFileForSomeReason' is imported by main.js, but could not be resolved – treating it as an external dependency. For help see https://github.com/rollup/rollup/wiki/Troubleshooting#treating-module-as-external-dependency` - ]); - }, + warnings: [ + { + code: 'UNRESOLVED_IMPORT', + message: `'unlessYouCreatedThisFileForSomeReason' is imported by main.js, but could not be resolved – treating it as an external dependency`, + url: `https://github.com/rollup/rollup/wiki/Troubleshooting#treating-module-as-external-dependency` + } + ], runtimeError: function ( error ) { assert.equal( "Cannot find module 'unlessYouCreatedThisFileForSomeReason'", error.message ); } diff --git a/test/function/double-named-export-from/_config.js b/test/function/double-named-export-from/_config.js deleted file mode 100644 index b3885d2..0000000 --- a/test/function/double-named-export-from/_config.js +++ /dev/null @@ -1,13 +0,0 @@ -const { resolve } = require('path'); -const assert = require( 'assert' ); - -const r = path => resolve( __dirname, path ); - -module.exports = { - description: 'throws on duplicate export * from', - warnings ( warnings ) { - assert.deepEqual( warnings, [ - `Conflicting namespaces: ${r('main.js')} re-exports 'foo' from both ${r('foo.js')} (will be ignored) and ${r('deep.js')}.` - ]); - } -}; diff --git a/test/function/empty-exports/_config.js b/test/function/empty-exports/_config.js index 8030197..e928a59 100644 --- a/test/function/empty-exports/_config.js +++ b/test/function/empty-exports/_config.js @@ -1,12 +1,23 @@ -const assert = require( 'assert' ); -const path = require( 'path' ); - module.exports = { description: 'warns on export {}, but does not fail', - warnings: warnings => { - assert.deepEqual( warnings, [ - `Module ${path.resolve( __dirname, 'main.js' )} has an empty export declaration`, - 'Generated an empty bundle' - ]); - } + warnings: [ + { + code: 'EMPTY_EXPORT', + message: 'Empty export declaration', + pos: 0, + loc: { + file: require( 'path' ).resolve( __dirname, 'main.js' ), + line: 1, + column: 0 + }, + frame: ` + 1: export {}; + ^ + ` + }, + { + code: 'EMPTY_BUNDLE', + message: 'Generated an empty bundle' + } + ] }; diff --git a/test/function/module-tree/_config.js b/test/function/module-tree/_config.js index 9662844..601ee7d 100644 --- a/test/function/module-tree/_config.js +++ b/test/function/module-tree/_config.js @@ -34,9 +34,10 @@ module.exports = { } ]); }, - warnings: warnings => { - assert.deepEqual( warnings, [ - 'Generated an empty bundle' - ]); - } + warnings: [ + { + code: 'EMPTY_BUNDLE', + message: 'Generated an empty bundle' + } + ] }; diff --git a/test/function/namespace-missing-export/_config.js b/test/function/namespace-missing-export/_config.js index 6ecf3b9..485a1ba 100644 --- a/test/function/namespace-missing-export/_config.js +++ b/test/function/namespace-missing-export/_config.js @@ -1,9 +1,21 @@ -var assert = require( 'assert' ); - module.exports = { - options: { - onwarn: function ( msg ) { - assert.equal( msg, `main.js (3:21) 'foo' is not exported by 'empty.js'. See https://github.com/rollup/rollup/wiki/Troubleshooting#name-is-not-exported-by-module` ); + warnings: [ + { + code: 'MISSING_EXPORT', + message: `'foo' is not exported by 'empty.js'`, + pos: 61, + loc: { + file: require( 'path' ).resolve( __dirname, 'main.js' ), + line: 3, + column: 25 + }, + frame: ` + 1: import * as mod from './empty.js'; + 2: + 3: assert.equal( typeof mod.foo, 'undefined' ); + ^ + `, + url: `https://github.com/rollup/rollup/wiki/Troubleshooting#name-is-not-exported-by-module` } - } + ] }; diff --git a/test/function/unused-import/_config.js b/test/function/unused-import/_config.js index b9e9b85..0f99f59 100644 --- a/test/function/unused-import/_config.js +++ b/test/function/unused-import/_config.js @@ -2,11 +2,19 @@ const assert = require( 'assert' ); module.exports = { description: 'warns on unused imports ([#595])', - warnings: warnings => { - assert.deepEqual( warnings, [ - `'external' is imported by main.js, but could not be resolved – treating it as an external dependency. For help see https://github.com/rollup/rollup/wiki/Troubleshooting#treating-module-as-external-dependency`, - `'unused', 'notused' and 'neverused' are imported from external module 'external' but never used`, - `Generated an empty bundle` - ]); - } + warnings: [ + { + code: 'UNRESOLVED_IMPORT', + message: `'external' is imported by main.js, but could not be resolved – treating it as an external dependency`, + url: `https://github.com/rollup/rollup/wiki/Troubleshooting#treating-module-as-external-dependency` + }, + { + code: 'UNUSED_EXTERNAL_IMPORT', + message: `'unused', 'notused' and 'neverused' are imported from external module 'external' but never used` + }, + { + code: 'EMPTY_BUNDLE', + message: `Generated an empty bundle` + } + ] }; diff --git a/test/function/warn-on-ambiguous-function-export/_config.js b/test/function/warn-on-ambiguous-function-export/_config.js index 1b83422..baa08bc 100644 --- a/test/function/warn-on-ambiguous-function-export/_config.js +++ b/test/function/warn-on-ambiguous-function-export/_config.js @@ -2,9 +2,23 @@ const assert = require( 'assert' ); module.exports = { description: 'uses original name of default export function (#1011)', - warnings: warnings => { - assert.deepEqual( warnings, [ - 'foo.js (1:15) Ambiguous default export (is a call expression, but looks like a function declaration). See https://github.com/rollup/rollup/wiki/Troubleshooting#ambiguous-default-export' - ]); - } + warnings: [ + { + code: 'AMBIGUOUS_DEFAULT_EXPORT', + message: `Ambiguous default export (is a call expression, but looks like a function declaration)`, + pos: 15, + loc: { + file: require( 'path' ).resolve( __dirname, 'foo.js' ), + line: 1, + column: 15 + }, + frame: ` + 1: export default function foo ( a, b ) { + ^ + 2: assert.equal( a, b ); + 3: return 3; + `, + url: `https://github.com/rollup/rollup/wiki/Troubleshooting#ambiguous-default-export` + } + ] }; diff --git a/test/function/warn-on-auto-named-default-exports/_config.js b/test/function/warn-on-auto-named-default-exports/_config.js index f093781..44e493b 100644 --- a/test/function/warn-on-auto-named-default-exports/_config.js +++ b/test/function/warn-on-auto-named-default-exports/_config.js @@ -1,10 +1,10 @@ -var assert = require( 'assert' ); - module.exports = { description: 'warns if default and named exports are used in auto mode', - warnings: function ( warnings ) { - assert.deepEqual( warnings, [ - 'Using named and default exports together. Consumers of your bundle will have to use bundle[\'default\'] to access the default export, which may not be what you want. Use `exports: \'named\'` to disable this warning. See https://github.com/rollup/rollup/wiki/JavaScript-API#exports for more information' - ]); - } + warnings: [ + { + code: 'MIXED_EXPORTS', + message: `Using named and default exports together. Consumers of your bundle will have to use bundle['default'] to access the default export, which may not be what you want. Use \`exports: 'named'\` to disable this warning`, + url: `https://github.com/rollup/rollup/wiki/JavaScript-API#exports` + } + ] }; diff --git a/test/function/warn-on-empty-bundle/_config.js b/test/function/warn-on-empty-bundle/_config.js index 2e599ad..a6d0a23 100644 --- a/test/function/warn-on-empty-bundle/_config.js +++ b/test/function/warn-on-empty-bundle/_config.js @@ -1,10 +1,9 @@ -const assert = require( 'assert' ); - module.exports = { description: 'warns if empty bundle is generated (#444)', - warnings: warnings => { - assert.deepEqual( warnings, [ - 'Generated an empty bundle' - ]); - } + warnings: [ + { + code: 'EMPTY_BUNDLE', + message: 'Generated an empty bundle' + } + ] }; diff --git a/test/function/warn-on-eval/_config.js b/test/function/warn-on-eval/_config.js index 7b499ef..a959bce 100644 --- a/test/function/warn-on-eval/_config.js +++ b/test/function/warn-on-eval/_config.js @@ -8,8 +8,12 @@ module.exports = { loc: { column: 13, file: require( 'path' ).resolve( __dirname, 'main.js' ), - line: 2 + line: 1 }, + frame: ` + 1: var result = eval( '1 + 1' ); + ^ + `, url: 'https://github.com/rollup/rollup/wiki/Troubleshooting#avoiding-eval' } ] diff --git a/test/function/warn-on-namespace-conflict/_config.js b/test/function/warn-on-namespace-conflict/_config.js new file mode 100644 index 0000000..2054d75 --- /dev/null +++ b/test/function/warn-on-namespace-conflict/_config.js @@ -0,0 +1,9 @@ +module.exports = { + description: 'warns on duplicate export * from', + warnings: [ + { + code: 'NAMESPACE_CONFLICT', + message: `Conflicting namespaces: main.js re-exports 'foo' from both foo.js (will be ignored) and deep.js` + } + ] +}; diff --git a/test/function/double-named-export-from/bar.js b/test/function/warn-on-namespace-conflict/bar.js similarity index 100% rename from test/function/double-named-export-from/bar.js rename to test/function/warn-on-namespace-conflict/bar.js diff --git a/test/function/double-named-export-from/deep.js b/test/function/warn-on-namespace-conflict/deep.js similarity index 100% rename from test/function/double-named-export-from/deep.js rename to test/function/warn-on-namespace-conflict/deep.js diff --git a/test/function/double-named-export-from/foo.js b/test/function/warn-on-namespace-conflict/foo.js similarity index 100% rename from test/function/double-named-export-from/foo.js rename to test/function/warn-on-namespace-conflict/foo.js diff --git a/test/function/double-named-export-from/main.js b/test/function/warn-on-namespace-conflict/main.js similarity index 100% rename from test/function/double-named-export-from/main.js rename to test/function/warn-on-namespace-conflict/main.js diff --git a/test/function/warn-on-top-level-this/_config.js b/test/function/warn-on-top-level-this/_config.js index 99c3f2c..4d9033e 100644 --- a/test/function/warn-on-top-level-this/_config.js +++ b/test/function/warn-on-top-level-this/_config.js @@ -2,11 +2,25 @@ const assert = require( 'assert' ); module.exports = { description: 'warns on top-level this (#770)', - warnings: warnings => { - assert.deepEqual( warnings, [ - `main.js (3:1) The 'this' keyword is equivalent to 'undefined' at the top level of an ES module, and has been rewritten. See https://github.com/rollup/rollup/wiki/Troubleshooting#this-is-undefined for more information` - ]); - }, + warnings: [ + { + code: 'THIS_IS_UNDEFINED', + message: `The 'this' keyword is equivalent to 'undefined' at the top level of an ES module, and has been rewritten`, + pos: 81, + loc: { + file: require( 'path' ).resolve( __dirname, 'main.js' ), + line: 3, + column: 0 + }, + frame: ` + 1: const someVariableJustToCheckOnCorrectLineNumber = true; // eslint-disable-line + 2: + 3: this.foo = 'bar'; + ^ + `, + url: `https://github.com/rollup/rollup/wiki/Troubleshooting#this-is-undefined` + } + ], runtimeError: err => { assert.equal( err.message, `Cannot set property 'foo' of undefined` ); } diff --git a/test/function/warn-on-unused-missing-imports/_config.js b/test/function/warn-on-unused-missing-imports/_config.js index 1fca512..08cc6ba 100644 --- a/test/function/warn-on-unused-missing-imports/_config.js +++ b/test/function/warn-on-unused-missing-imports/_config.js @@ -3,9 +3,22 @@ const assert = require( 'assert' ); module.exports = { description: 'warns on missing (but unused) imports', - warnings: warnings => { - assert.deepEqual( warnings, [ - `Non-existent export 'b' is imported from ${path.resolve(__dirname, 'foo.js')} by ${path.resolve(__dirname, 'main.js')}` - ]); - } + warnings: [ + { + code: 'NON_EXISTENT_EXPORT', + message: `Non-existent export 'b' is imported from foo.js`, + pos: 12, + loc: { + file: path.resolve( __dirname, 'main.js' ), + line: 1, + column: 12 + }, + frame: ` + 1: import { a, b } from './foo.js'; + ^ + 2: + 3: assert.equal( a, 42 ); + ` + } + ] }; diff --git a/test/sourcemaps/transform-without-sourcemap/_config.js b/test/sourcemaps/transform-without-sourcemap/_config.js index ad33354..0ce79c0 100644 --- a/test/sourcemaps/transform-without-sourcemap/_config.js +++ b/test/sourcemaps/transform-without-sourcemap/_config.js @@ -1,10 +1,5 @@ -const assert = require( 'assert' ); - -let warnings = []; - module.exports = { description: 'preserves sourcemap chains when transforming', - before: () => warnings = [], // reset options: { plugins: [ { @@ -13,14 +8,13 @@ module.exports = { return code; } } - ], - onwarn ( msg ) { - warnings.push( msg ); - } + ] }, - test: () => { - assert.deepEqual( warnings, [ - `Sourcemap is likely to be incorrect: a plugin ('fake plugin') was used to transform files, but didn't generate a sourcemap for the transformation. Consult https://github.com/rollup/rollup/wiki/Troubleshooting and the plugin documentation for more information` - ]); - } + warnings: [ + { + code: `SOURCEMAP_BROKEN`, + message: `Sourcemap is likely to be incorrect: a plugin ('fake plugin') was used to transform files, but didn't generate a sourcemap for the transformation. Consult the plugin documentation for help`, + url: `https://github.com/rollup/rollup/wiki/Troubleshooting#sourcemap-is-likely-to-be-incorrect` + } + ] }; diff --git a/test/test.js b/test/test.js index 8b1d3cf..789ac44 100644 --- a/test/test.js +++ b/test/test.js @@ -58,6 +58,27 @@ function loader ( modules ) { }; } +function compareWarnings ( actual, expected ) { + assert.deepEqual( + actual.map( warning => { + const clone = Object.assign( {}, warning ); + delete clone.toString; + + if ( clone.frame ) { + clone.frame = clone.frame.replace( /\s+$/gm, '' ); + } + + return clone; + }), + expected.map( warning => { + if ( warning.frame ) { + warning.frame = warning.frame.slice( 1 ).replace( /^\t+/gm, '' ).replace( /\s+$/gm, '' ).trim(); + } + return warning; + }) + ); +} + describe( 'rollup', function () { this.timeout( 10000 ); @@ -271,13 +292,7 @@ describe( 'rollup', function () { if ( config.warnings ) { if ( Array.isArray( config.warnings ) ) { - assert.deepEqual( warnings.map( warning => { - const clone = Object.assign( {}, warning ); - delete clone.toString; - delete clone.frame; - - return clone; - }), config.warnings ); + compareWarnings( warnings, config.warnings ); } else { config.warnings( warnings ); } @@ -387,11 +402,18 @@ describe( 'rollup', function () { const entry = path.resolve( SOURCEMAPS, dir, 'main.js' ); const dest = path.resolve( SOURCEMAPS, dir, '_actual/bundle' ); - const options = extend( {}, config.options, { entry }); + let warnings; + + const options = extend( {}, config.options, { + entry, + onwarn: warning => warnings.push( warning ) + }); PROFILES.forEach( profile => { ( config.skip ? it.skip : config.solo ? it.only : it )( 'generates ' + profile.format, () => { process.chdir( SOURCEMAPS + '/' + dir ); + warnings = []; + return rollup.rollup( options ).then( bundle => { const options = extend( {}, { format: profile.format, @@ -401,9 +423,16 @@ describe( 'rollup', function () { bundle.write( options ); - if ( config.before ) config.before(); - const result = bundle.generate( options ); - config.test( result.code, result.map ); + if ( config.test ) { + const { code, map } = bundle.generate( options ); + config.test( code, map ); + } + + if ( config.warnings ) { + compareWarnings( warnings, config.warnings ); + } else if ( warnings.length ) { + throw new Error( `Unexpected warnings` ); + } }); }); }); @@ -747,11 +776,9 @@ describe( 'rollup', function () { moduleName: 'myBundle' }); - assert.deepEqual( warnings, [ - `'util' is imported by entry, but could not be resolved – treating it as an external dependency. For help see https://github.com/rollup/rollup/wiki/Troubleshooting#treating-module-as-external-dependency`, - `Creating a browser bundle that depends on Node.js built-in module ('util'). You might need to include https://www.npmjs.com/package/rollup-plugin-node-builtins`, - `No name was provided for external module 'util' in options.globals – guessing 'util'` - ]); + const relevantWarnings = warnings.filter( warning => warning.code === 'MISSING_NODE_BUILTINS' ); + assert.equal( relevantWarnings.length, 1 ); + assert.equal( relevantWarnings[0].message, `Creating a browser bundle that depends on Node.js built-in module ('util'). You might need to include https://www.npmjs.com/package/rollup-plugin-node-builtins` ); }); }); });