import assert from "assert";
import { svelte, deindent, env, setupHtmlEqual } from "../helpers.js";
function testAmd(code, expectedId, dependencies, html) {
	const fn = new Function("define", code);
	const window = env();
	function define(id, deps, factory) {
		assert.equal(id, expectedId);
		assert.deepEqual(deps, Object.keys(dependencies));
		const SvelteComponent = factory(
			...Object.keys(dependencies).map(key => dependencies[key])
		);
		const main = window.document.body.querySelector("main");
		const component = new SvelteComponent({ target: main });
		assert.htmlEqual(main.innerHTML, html);
		component.destroy();
	}
	define.amd = true;
	fn(define);
}
function testCjs(code, dependencyById, html) {
	const fn = new Function("module", "exports", "require", code);
	const window = env();
	const module = { exports: {} };
	const require = id => {
		return dependencyById[id];
	};
	fn(module, module.exports, require);
	const SvelteComponent = module.exports;
	const main = window.document.body.querySelector("main");
	const component = new SvelteComponent({ target: main });
	assert.htmlEqual(main.innerHTML, html);
	component.destroy();
}
function testIife(code, name, globals, html) {
	const fn = new Function(Object.keys(globals), `${code}\n\nreturn ${name};`);
	const window = env();
	const SvelteComponent = fn(
		...Object.keys(globals).map(key => globals[key])
	);
	const main = window.document.body.querySelector("main");
	const component = new SvelteComponent({ target: main });
	assert.htmlEqual(main.innerHTML, html);
	component.destroy();
}
function testEval(code, name, globals, html) {
	const fn = new Function(Object.keys(globals), `return ${code};`);
	const window = env();
	const SvelteComponent = fn(
		...Object.keys(globals).map(key => globals[key])
	);
	const main = window.document.body.querySelector("main");
	const component = new SvelteComponent({ target: main });
	assert.htmlEqual(main.innerHTML, html);
	component.destroy();
}
describe("formats", () => {
	before(setupHtmlEqual);
	describe("amd", () => {
		it("generates an AMD module", () => {
			const source = deindent`
				
{{answer}}
				
			`;
			const { code } = svelte.compile(source, {
				format: "amd",
				amd: { id: "foo" }
			});
			return testAmd(code, "foo", { answer: 42 }, `42
`);
		});
	});
	describe("cjs", () => {
		it("generates a CommonJS module", () => {
			const source = deindent`
				{{answer}}
				
			`;
			const { code } = svelte.compile(source, {
				format: "cjs"
			});
			return testCjs(code, { answer: 42 }, `42
`);
		});
	});
	describe("iife", () => {
		it("generates a self-executing script", () => {
			const source = deindent`
				{{answer}}
				
			`;
			const { code } = svelte.compile(source, {
				format: "iife",
				name: "Foo",
				globals: {
					answer: "answer"
				}
			});
			return testIife(code, "Foo", { answer: 42 }, `42
`);
		});
		it('requires options.name', () => {
			assert.throws(() => {
				svelte.compile('', {
					format: 'iife'
				});
			}, /Missing required 'name' option for IIFE export/);
		});
		it('suggests using options.globals for default imports', () => {
			const warnings = [];
			svelte.compile(`
				
			`,
				{
					format: 'iife',
					name: 'App',
					onwarn: warning => {
						warnings.push(warning);
					}
				}
			);
			assert.deepEqual(warnings, [{
				code: `options-missing-globals`,
				message: `No name was supplied for imported module 'lodash'. Guessing '_', but you should use options.globals`
			}]);
		});
		it('insists on options.globals for named imports', () => {
			assert.throws(() => {
				svelte.compile(`
					
				`,
					{
						format: 'iife',
						name: 'App'
					}
				);
			}, /Could not determine name for imported module 'svelte-transitions' – use options.globals/);
		});
	});
	describe("umd", () => {
		it("generates a UMD build", () => {
			const source = deindent`
				{{answer}}
				
			`;
			const { code } = svelte.compile(source, {
				format: "umd",
				name: "Foo",
				globals: {
					answer: "answer"
				},
				amd: {
					id: "foo"
				}
			});
			testAmd(code, "foo", { answer: 42 }, `42
`);
			testCjs(code, { answer: 42 }, `42
`);
			testIife(code, "Foo", { answer: 42 }, `42
`);
		});
		it('requires options.name', () => {
			assert.throws(() => {
				svelte.compile('', {
					format: 'umd'
				});
			}, /Missing required 'name' option for UMD export/);
		});
	});
	describe("eval", () => {
		it("generates a self-executing script that returns the component on eval", () => {
			const source = deindent`
				{{answer}}
				
			`;
			const { code } = svelte.compile(source, {
				format: "eval",
				globals: {
					answer: "answer"
				}
			});
			return testEval(code, "Foo", { answer: 42 }, `42
`);
		});
	});
	describe('unknown format', () => {
		it('throws an error', () => {
			assert.throws(() => {
				svelte.compile('', {
					format: 'nope'
				});
			}, /options.format is invalid \(must be es, amd, cjs, iife, umd or eval\)/);
		});
	});
});