text: const assert = require('assert');
  const acorn = require('acorn');
  const { executeBundle } = require('../utils.js');
  const rollup = require('../../dist/rollup');
  
  describe('incremental', () => {
  	let resolveIdCalls;
  	let transformCalls;
  	let modules;
  
  	const plugin = {
  		resolveId: id => {
  			resolveIdCalls += 1;
  			return id === 'external' ? false : id;
  		},
  
  		load: id => {
  			return modules[id];
  		},
  
  		transform: code => {
  			transformCalls += 1;
  			return code;
  		}
  	};
  
  	beforeEach(() => {
  		resolveIdCalls = 0;
  		transformCalls = 0;
  
  		modules = {
  			entry: `import foo from 'foo'; export default foo;`,
  			foo: `export default 42`,
  			bar: `export default 21`
  		};
  	});
  
  	it('does not resolve ids and transforms in the second time', () => {
  		return rollup
  			.rollup({
  				input: 'entry',
  				plugins: [plugin]
  			})
  			.then(bundle => {
  				assert.equal(resolveIdCalls, 2);
  				assert.equal(transformCalls, 2);
  				return rollup.rollup({
  					input: 'entry',
  					plugins: [plugin],
  					cache: bundle
  				});
  			})
  			.then(bundle => {
  				assert.equal(resolveIdCalls, 3); // +1 for entry point which is resolved every time
  				assert.equal(transformCalls, 2);
  
  				return executeBundle(bundle);
  			})
  			.then(result => {
  				assert.equal(result, 42);
  			});
  	});
  
  	it('does not resolve dynamic ids and transforms in the second time', () => {
  		modules = {
  			entry: `export default import('foo');`,
  			foo: `export default 42`
  		};
  		return rollup
  			.rollup({
  				input: 'entry',
  				plugins: [plugin]
  			})
  			.then(bundle => {
  				assert.equal(resolveIdCalls, 2);
  				assert.equal(transformCalls, 2);
  				return rollup.rollup({
  					input: 'entry',
  					plugins: [plugin],
  					cache: bundle
  				});
  			})
  			.then(bundle => {
  				assert.equal(resolveIdCalls, 3); // +1 for entry point which is resolved every time
  				assert.equal(transformCalls, 2);
  			});
  	});
  
  	it('transforms modified sources', () => {
  		let cache;
  
  		return rollup
  			.rollup({
  				input: 'entry',
  				plugins: [plugin]
  			})
  			.then(bundle => {
  				assert.equal(transformCalls, 2);
  
  				return executeBundle(bundle).then(result => {
  					assert.equal(result, 42);
  
  					modules.foo = `export default 43`;
  					cache = bundle.cache;
  				});
  			})
  			.then(() => {
  				return rollup.rollup({
  					input: 'entry',
  					plugins: [plugin],
  					cache
  				});
  			})
  			.then(bundle => {
  				assert.equal(transformCalls, 3);
  
  				return executeBundle(bundle);
  			})
  			.then(result => {
  				assert.equal(result, 43);
  			});
  	});
  
  	it('resolves id of new imports', () => {
  		let cache;
  
  		return rollup
  			.rollup({
  				input: 'entry',
  				plugins: [plugin]
  			})
  			.then(bundle => {
  				assert.equal(resolveIdCalls, 2);
  
  				return executeBundle(bundle).then(result => {
  					assert.equal(result, 42);
  
  					modules.entry = `import bar from 'bar'; export default bar;`;
  					cache = bundle.cache;
  				});
  			})
  			.then(() => {
  				return rollup.rollup({
  					input: 'entry',
  					plugins: [plugin],
  					cache
  				});
  			})
  			.then(bundle => {
  				assert.equal(resolveIdCalls, 4);
  
  				return executeBundle(bundle);
  			})
  			.then(result => {
  				assert.equal(result, 21);
  			});
  	});
  
  	it('respects externals from resolveId', () => {
  		let cache;
  		modules.foo = `import p from 'external'; export default p;`;
  
  		const require = id => id === 'external' && 43;
  
  		return rollup
  			.rollup({
  				input: 'entry',
  				plugins: [plugin]
  			})
  			.then(bundle => {
  				assert.equal(resolveIdCalls, 3);
  
  				return executeBundle(bundle, require).then(result => {
  					assert.equal(result, 43);
  					cache = bundle.cache;
  				});
  			})
  			.then(() => {
  				return rollup.rollup({
  					input: 'entry',
  					plugins: [plugin],
  					cache
  				});
  			})
  			.then(bundle => {
  				assert.equal(resolveIdCalls, 4);
  
  				return executeBundle(bundle, require);
  			})
  			.then(result => {
  				assert.equal(result, 43);
  			});
  	});
  
  	it('keeps ASTs between runs', () => {
  		return rollup
  			.rollup({
  				input: 'entry',
  				plugins: [plugin]
  			})
  			.then(bundle => {
  				const asts = {};
  				bundle.cache.modules.forEach(module => {
  					asts[module.id] = module.ast;
  				});
  
  				assert.deepEqual(
  					asts.entry,
  					acorn.parse(modules.entry, { sourceType: 'module', ecmaVersion: 2020 })
  				);
  				assert.deepEqual(
  					asts.foo,
  					acorn.parse(modules.foo, { sourceType: 'module', ecmaVersion: 2020 })
  				);
  			});
  	});
  
  	it('recovers from errors', () => {
  		modules.entry = `import foo from 'foo'; import bar from 'bar'; export default foo + bar;`;
  
  		return rollup
  			.rollup({
  				input: 'entry',
  				plugins: [plugin]
  			})
  			.then(cache => {
  				modules.foo = `var 42 = nope;`;
  
  				return rollup
  					.rollup({
  						input: 'entry',
  						plugins: [plugin],
  						cache
  					})
  					.catch(err => {
  						return cache;
  					});
  			})
  			.then(cache => {
  				modules.foo = `export default 42;`;
  
  				return rollup
  					.rollup({
  						input: 'entry',
  						plugins: [plugin],
  						cache
  					})
  					.then(bundle => {
  						return executeBundle(bundle);
  					})
  					.then(result => {
  						assert.equal(result, 63);
  					});
  			});
  	});
  
  	it('combines resolvedIds from resolvedExternalIds', () => {
  		modules = {
  			entry: `import foo from 'foo'; import external from 'external'; console.log(foo(external));`,
  			foo: `export default 42`
  		};
  
  		return rollup
  			.rollup({
  				input: 'entry',
  				external: ['external'],
  				plugins: [plugin]
  			})
  			.then(bundle => {
  				assert.equal(bundle.cache.modules[0].id, 'foo');
  				assert.equal(bundle.cache.modules[1].id, 'entry');
  
  				assert.deepEqual(bundle.cache.modules[1].resolvedIds, {
  					foo: {
  						id: 'foo',
  						external: false,
  						moduleSideEffects: true,
  						syntheticNamedExports: false
  					},
  					external: {
  						id: 'external',
  						external: true,
  						moduleSideEffects: true,
  						syntheticNamedExports: false
  					}
  				});
  			});
  	});
  });
  