import * as fs from 'fs'; import * as path from 'path'; import * as assert from 'assert'; import { loadConfig, svelte } from '../helpers'; // keep source-map at version 0.7.x // https://github.com/mozilla/source-map/issues/400 import { getLocator } from 'locate-character'; import { SourceMapConsumer } from 'source-map'; describe('sourcemaps', () => { fs.readdirSync(`${__dirname}/samples`).forEach(dir => { if (dir[0] === '.') return; const config = loadConfig(`${__dirname}/samples/${dir}/_config.js`); // add .solo to a sample directory name to only run that test const solo = config.solo || /\.solo/.test(dir); const skip = config.skip || /\.skip/.test(dir); if (solo && process.env.CI) { throw new Error('Forgot to remove `solo: true` from test'); } (solo ? it.only : skip ? it.skip : it)(dir, async () => { const { test } = require(`./samples/${dir}/test.js`); const inputFile = path.resolve(`${__dirname}/samples/${dir}/input.svelte`); const outputName = '_actual'; const outputBase = path.resolve(`${__dirname}/samples/${dir}/${outputName}`); const inputCode = fs.readFileSync(inputFile, 'utf-8'); const input = { code: inputCode, locate: getLocator(inputCode), locate_1: getLocator(inputCode, { offsetLine: 1 }) }; const preprocessed = await svelte.preprocess( input.code, config.preprocess || {}, config.options || { filename: 'input.svelte' } ); const { js, css } = svelte.compile( preprocessed.code, { filename: 'input.svelte', // filenames for sourcemaps sourcemap: preprocessed.map, outputFilename: `${outputName}.js`, cssOutputFilename: `${outputName}.css`, ...(config.compile_options || {}) }); js.code = js.code.replace( /generated by Svelte v\d+\.\d+\.\d+/, match => match.replace(/\d/g, 'x') ); fs.writeFileSync(`${outputBase}.svelte`, preprocessed.code); if (preprocessed.map) { fs.writeFileSync( `${outputBase}.svelte.map`, // TODO encode mappings for output - svelte.preprocess returns decoded mappings JSON.stringify(preprocessed.map, null, 2) ); } fs.writeFileSync( `${outputBase}.js`, `${js.code}\n//# sourceMappingURL=${outputName}.js.map` ); fs.writeFileSync( `${outputBase}.js.map`, JSON.stringify(js.map, null, 2) ); if (css.code) { fs.writeFileSync( `${outputBase}.css`, `${css.code}\n/*# sourceMappingURL=${outputName}.css.map */` ); fs.writeFileSync( `${outputBase}.css.map`, JSON.stringify(css.map, null, ' ') ); } if (js.map) { assert.deepEqual( js.map.sources.slice().sort(), (config.js_map_sources || ['input.svelte']).sort(), 'js.map.sources is wrong' ); } if (css.map) { assert.deepEqual( css.map.sources.slice().sort(), (config.css_map_sources || ['input.svelte']).sort(), 'css.map.sources is wrong' ); } // use locate_1 with mapConsumer: // lines are one-based, columns are zero-based preprocessed.mapConsumer = preprocessed.map && await new SourceMapConsumer(preprocessed.map); preprocessed.locate = getLocator(preprocessed.code); preprocessed.locate_1 = getLocator(preprocessed.code, { offsetLine: 1 }); js.mapConsumer = js.map && await new SourceMapConsumer(js.map); js.locate = getLocator(js.code); js.locate_1 = getLocator(js.code, { offsetLine: 1 }); css.mapConsumer = css.map && await new SourceMapConsumer(css.map); css.locate = getLocator(css.code || ''); css.locate_1 = getLocator(css.code || '', { offsetLine: 1 }); await test({ assert, input, preprocessed, js, css }); }); }); });