Skip to content

Commit

Permalink
fix: source maps
Browse files Browse the repository at this point in the history
  • Loading branch information
huafu committed Aug 19, 2018
1 parent 70a61f6 commit 89a30c9
Show file tree
Hide file tree
Showing 14 changed files with 242 additions and 49 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ node_js:
- "6"

script:
- npm run clean -- --when-ci-commit-message
- npm run test -- --coverage
5 changes: 3 additions & 2 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# http://www.appveyor.com/docs/appveyor-yml
init:
- ps: IF ($env:APPVEYOR_REPO_COMMIT_MESSAGE -Match "\[clear ci-cache\]" ) {$env:APPVEYOR_CACHE_SKIP_RESTORE = "true"}
- ps: IF ($env:APPVEYOR_REPO_COMMIT_MESSAGE_EXTENDED -Match "\[clear ci-cache\]") {$env:APPVEYOR_CACHE_SKIP_RESTORE = "true"}
- ps: IF ($env:APPVEYOR_REPO_COMMIT_MESSAGE -Match "\[clean ci-cache\]" ) {$env:APPVEYOR_CACHE_SKIP_RESTORE = "true"}
- ps: IF ($env:APPVEYOR_REPO_COMMIT_MESSAGE_EXTENDED -Match "\[clean ci-cache\]") {$env:APPVEYOR_CACHE_SKIP_RESTORE = "true"}

# Test against these versions of Node.js.
environment:
Expand All @@ -20,6 +20,7 @@ install:
- set TS_JEST_E2E_WORKDIR=%APPDATA%\ts-jest-e2e
- npm version
- npm ci || npm install
- npm run clean -- --when-ci-commit-message

cache:
- '%APPDATA%\npm-cache -> package.json'
Expand Down
1 change: 1 addition & 0 deletions e2e/__helpers__/source-maps.ts
17 changes: 14 additions & 3 deletions e2e/__helpers__/test-case.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { sync as spawnSync } from 'cross-spawn'
import { join, relative, sep } from 'path'
import * as Paths from '../../scripts/paths'
import * as fs from 'fs-extra'
import { RawSourceMap } from 'source-map'
import { relativiseSourceRoot, extractSourceMaps } from './source-maps'

const TEMPLATE_EXCLUDED_ITEMS = ['node_modules', 'package-lock.json']

Expand Down Expand Up @@ -79,7 +81,7 @@ class TestCaseRunDescriptor {
if (logUnlessStatus != null && logUnlessStatus !== result.status) {
console.log(
`Output of test run in "${this.name}" using template "${
this.templateName
this.templateName
}" (exit code: ${result.status}):\n\n`,
result.output.trim(),
)
Expand Down Expand Up @@ -147,8 +149,9 @@ export interface TestRunResult {
}
interface TestFileIoData {
in: [string, jest.Path, jest.ProjectConfig, jest.TransformOptions?]
// out: string | jest.TransformedSource;
out: string
outNormalized: string
outSourceMaps: RawSourceMap
}

// tslint:disable-next-line:interface-over-type-literal
Expand Down Expand Up @@ -292,12 +295,20 @@ export function run(name: string, options: RunTestOptions = {}): TestRunResult {
}
if (writeIo) {
Object.defineProperty(res, 'ioDataFor', {
value: (relPath: string) => require(`${ioDir}/${relPath}.json`),
value: (relPath: string) => wrapIoData(require(`${ioDir}/${relPath}.json`), dir),
})
}
return res as any
}

function wrapIoData(ioData: TestFileIoData, rootDir: string): TestFileIoData {
const res: TestFileIoData = { ...ioData }
return Object.defineProperties(res, {
outNormalized: { get: () => relativiseSourceRoot(rootDir, ioData.out, '<cwd>/') },
outSourceMaps: { get: () => extractSourceMaps(ioData.out) },
})
}

// from https://stackoverflow.com/questions/25245716/remove-all-ansi-colors-styles-from-strings
function stripAnsiColors(stringToStrip: string): string {
return stringToStrip.replace(
Expand Down
8 changes: 4 additions & 4 deletions e2e/__tests__/__snapshots__/source-map.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function throwError() {
throw new Error('WITHIN SOURCE');
}
exports.throwError = throwError;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJmaWxlIjoiL3ByaXZhdGUvdmFyL2ZvbGRlcnMvZHIvZHlnM192MzEzempmcHE4MndkXzRiMGxyMDAwMGduL1QvLS10cy1qZXN0LXRlbXAtZTJlLS0vZGVmYXVsdC9zb3VyY2UtbWFwcy9tYWluLnRzIiwibWFwcGluZ3MiOiI7O0FBQUE7SUFDRSxPQUFPLENBQUMsR0FBRyxDQUFDLGVBQWUsQ0FBQyxDQUFDO0FBQy9CLENBQUM7QUFGRCxnQ0FFQztBQUVEO0lBQ0UsTUFBTSxJQUFJLEtBQUssQ0FBQyxlQUFlLENBQUMsQ0FBQztBQUNuQyxDQUFDO0FBRkQsZ0NBRUMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiL3ByaXZhdGUvdmFyL2ZvbGRlcnMvZHIvZHlnM192MzEzempmcHE4MndkXzRiMGxyMDAwMGduL1QvLS10cy1qZXN0LXRlbXAtZTJlLS0vZGVmYXVsdC9zb3VyY2UtbWFwcy9tYWluLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBmdW5jdGlvbiBjb25zb2xlTG9nKCkge1xuICBjb25zb2xlLmxvZygnV0lUSElOIFNPVVJDRScpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdGhyb3dFcnJvcigpIHtcbiAgdGhyb3cgbmV3IEVycm9yKCdXSVRISU4gU09VUkNFJyk7XG59XG4iXSwidmVyc2lvbiI6M30="
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJmaWxlIjoibWFpbi50cyIsIm1hcHBpbmdzIjoiOztBQUFBO0lBQ0UsT0FBTyxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUMsQ0FBQztBQUMvQixDQUFDO0FBRkQsZ0NBRUM7QUFFRDtJQUNFLE1BQU0sSUFBSSxLQUFLLENBQUMsZUFBZSxDQUFDLENBQUM7QUFDbkMsQ0FBQztBQUZELGdDQUVDIiwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiPGN3ZD4vIiwic291cmNlcyI6WyJtYWluLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBmdW5jdGlvbiBjb25zb2xlTG9nKCkge1xuICBjb25zb2xlLmxvZygnV0lUSElOIFNPVVJDRScpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdGhyb3dFcnJvcigpIHtcbiAgdGhyb3cgbmV3IEVycm9yKCdXSVRISU4gU09VUkNFJyk7XG59XG4iXSwidmVyc2lvbiI6M30="
`;

exports[`using template "default" should report correct line numbers 1`] = `
Expand Down Expand Up @@ -79,7 +79,7 @@ function throwError() {
throw new Error('WITHIN SOURCE');
}
exports.throwError = throwError;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9wcml2YXRlL3Zhci9mb2xkZXJzL2RyL2R5ZzNfdjMxM3pqZnBxODJ3ZF80YjBscjAwMDBnbi9ULy0tdHMtamVzdC10ZW1wLWUyZS0tL3dpdGgtYmFiZWwtNi9zb3VyY2UtbWFwcy9tYWluLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLFNBQUEsVUFBQSxHQUFBO0FBQ0UsWUFBUSxHQUFSLENBQVksZUFBWjtBQUNEO0FBRkQsUUFBQSxVQUFBLEdBQUEsVUFBQTtBQUlBLFNBQUEsVUFBQSxHQUFBO0FBQ0UsVUFBTSxJQUFJLEtBQUosQ0FBVSxlQUFWLENBQU47QUFDRDtBQUZELFFBQUEsVUFBQSxHQUFBLFVBQUEiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgZnVuY3Rpb24gY29uc29sZUxvZygpIHtcbiAgY29uc29sZS5sb2coJ1dJVEhJTiBTT1VSQ0UnKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHRocm93RXJyb3IoKSB7XG4gIHRocm93IG5ldyBFcnJvcignV0lUSElOIFNPVVJDRScpO1xufVxuIl19"
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJtYXBwaW5ncyI6Ijs7O0FBQUEsU0FBQSxVQUFBLEdBQUE7QUFDRSxZQUFRLEdBQVIsQ0FBWSxlQUFaO0FBQ0Q7QUFGRCxRQUFBLFVBQUEsR0FBQSxVQUFBO0FBSUEsU0FBQSxVQUFBLEdBQUE7QUFDRSxVQUFNLElBQUksS0FBSixDQUFVLGVBQVYsQ0FBTjtBQUNEO0FBRkQsUUFBQSxVQUFBLEdBQUEsVUFBQSIsIm5hbWVzIjpbXSwic291cmNlUm9vdCI6Ijxjd2Q+LyIsInNvdXJjZXMiOlsibWFpbi50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgZnVuY3Rpb24gY29uc29sZUxvZygpIHtcbiAgY29uc29sZS5sb2coJ1dJVEhJTiBTT1VSQ0UnKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHRocm93RXJyb3IoKSB7XG4gIHRocm93IG5ldyBFcnJvcignV0lUSElOIFNPVVJDRScpO1xufVxuIl0sInZlcnNpb24iOjN9"
`;
exports[`using template "with-babel-6" should report correct line numbers 1`] = `
Expand Down Expand Up @@ -153,7 +153,7 @@ function throwError() {
}
exports.throwError = throwError;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9wcml2YXRlL3Zhci9mb2xkZXJzL2RyL2R5ZzNfdjMxM3pqZnBxODJ3ZF80YjBscjAwMDBnbi9ULy0tdHMtamVzdC10ZW1wLWUyZS0tL3dpdGgtYmFiZWwtNy9zb3VyY2UtbWFwcy9tYWluLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLFNBQUEsVUFBQSxHQUFBO0FBQ0UsRUFBQSxPQUFPLENBQUMsR0FBUixDQUFZLGVBQVo7QUFDRDs7QUFGRCxPQUFBLENBQUEsVUFBQSxHQUFBLFVBQUE7O0FBSUEsU0FBQSxVQUFBLEdBQUE7QUFDRSxRQUFNLElBQUksS0FBSixDQUFVLGVBQVYsQ0FBTjtBQUNEOztBQUZELE9BQUEsQ0FBQSxVQUFBLEdBQUEsVUFBQSIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBmdW5jdGlvbiBjb25zb2xlTG9nKCkge1xuICBjb25zb2xlLmxvZygnV0lUSElOIFNPVVJDRScpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdGhyb3dFcnJvcigpIHtcbiAgdGhyb3cgbmV3IEVycm9yKCdXSVRISU4gU09VUkNFJyk7XG59XG4iXX0="
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsU0FBQSxVQUFBLEdBQUE7QUFDRSxFQUFBLE9BQU8sQ0FBQyxHQUFSLENBQVksZUFBWjtBQUNEOztBQUZELE9BQUEsQ0FBQSxVQUFBLEdBQUEsVUFBQTs7QUFJQSxTQUFBLFVBQUEsR0FBQTtBQUNFLFFBQU0sSUFBSSxLQUFKLENBQVUsZUFBVixDQUFOO0FBQ0Q7O0FBRkQsT0FBQSxDQUFBLFVBQUEsR0FBQSxVQUFBIiwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiPGN3ZD4vIiwic291cmNlcyI6WyJtYWluLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBmdW5jdGlvbiBjb25zb2xlTG9nKCkge1xuICBjb25zb2xlLmxvZygnV0lUSElOIFNPVVJDRScpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdGhyb3dFcnJvcigpIHtcbiAgdGhyb3cgbmV3IEVycm9yKCdXSVRISU4gU09VUkNFJyk7XG59XG4iXSwidmVyc2lvbiI6M30="
`;
exports[`using template "with-babel-7" should report correct line numbers 1`] = `
Expand Down Expand Up @@ -220,7 +220,7 @@ function throwError() {
throw new Error('WITHIN SOURCE');
}
exports.throwError = throwError;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJmaWxlIjoiL3ByaXZhdGUvdmFyL2ZvbGRlcnMvZHIvZHlnM192MzEzempmcHE4MndkXzRiMGxyMDAwMGduL1QvLS10cy1qZXN0LXRlbXAtZTJlLS0vd2l0aC1qZXN0LTIyL3NvdXJjZS1tYXBzL21haW4udHMiLCJtYXBwaW5ncyI6Ijs7QUFBQTtJQUNFLE9BQU8sQ0FBQyxHQUFHLENBQUMsZUFBZSxDQUFDLENBQUM7QUFDL0IsQ0FBQztBQUZELGdDQUVDO0FBRUQ7SUFDRSxNQUFNLElBQUksS0FBSyxDQUFDLGVBQWUsQ0FBQyxDQUFDO0FBQ25DLENBQUM7QUFGRCxnQ0FFQyIsIm5hbWVzIjpbXSwic291cmNlcyI6WyIvcHJpdmF0ZS92YXIvZm9sZGVycy9kci9keWczX3YzMTN6amZwcTgyd2RfNGIwbHIwMDAwZ24vVC8tLXRzLWplc3QtdGVtcC1lMmUtLS93aXRoLWplc3QtMjIvc291cmNlLW1hcHMvbWFpbi50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgZnVuY3Rpb24gY29uc29sZUxvZygpIHtcbiAgY29uc29sZS5sb2coJ1dJVEhJTiBTT1VSQ0UnKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHRocm93RXJyb3IoKSB7XG4gIHRocm93IG5ldyBFcnJvcignV0lUSElOIFNPVVJDRScpO1xufVxuIl0sInZlcnNpb24iOjN9"
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJmaWxlIjoibWFpbi50cyIsIm1hcHBpbmdzIjoiOztBQUFBO0lBQ0UsT0FBTyxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUMsQ0FBQztBQUMvQixDQUFDO0FBRkQsZ0NBRUM7QUFFRDtJQUNFLE1BQU0sSUFBSSxLQUFLLENBQUMsZUFBZSxDQUFDLENBQUM7QUFDbkMsQ0FBQztBQUZELGdDQUVDIiwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiPGN3ZD4vIiwic291cmNlcyI6WyJtYWluLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBmdW5jdGlvbiBjb25zb2xlTG9nKCkge1xuICBjb25zb2xlLmxvZygnV0lUSElOIFNPVVJDRScpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdGhyb3dFcnJvcigpIHtcbiAgdGhyb3cgbmV3IEVycm9yKCdXSVRISU4gU09VUkNFJyk7XG59XG4iXSwidmVyc2lvbiI6M30="
`;
exports[`using template "with-jest-22" should report correct line numbers 1`] = `
Expand Down
2 changes: 1 addition & 1 deletion e2e/__tests__/source-map.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ testCase.runWithTemplates(allPackageSets, 1, (runTest, { templateName }) => {
// when there are some issues with debugging, it's usually becasue source mpas are not inlined
// and the debugger cannot find the line where to go
it(`should have the source mpas comment`, () => {
expect(result.ioDataFor('main.ts').out).toMatchSnapshot()
expect(result.ioDataFor('main.ts').outNormalized).toMatchSnapshot()
})
})
})
47 changes: 44 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
"prettier-tslint": "^0.4.0",
"reflect-metadata": "^0.1.12",
"semver": "^5.5.1",
"source-map": "^0.7.3",
"tslint": "^5.11.0",
"typescript": "^3.0.1"
},
Expand Down
34 changes: 23 additions & 11 deletions scripts/clean.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
#!/usr/bin/env node

const { removeSync } = require('fs-extra');
const Paths = require('./paths');
const { join } = require('path');
const { removeSync } = require('fs-extra')
const Paths = require('./paths')
const { join } = require('path')

removeSync(Paths.distDir);
removeSync(join(Paths.testsRootDir, '*', 'coverage'));
removeSync(join(Paths.testsRootDir, '*', 'debug.txt'));
removeSync(join(Paths.testsRootDir, '*', 'node_modules'));
removeSync(join(Paths.e2eSourceDir, '*', 'node_modules'));
removeSync(join(Paths.e2eTemplatesDir, '*', 'node_modules'));
removeSync(Paths.e2eWorkDir);
removeSync(Paths.e2eWotkDirLink);
if (process.argv.indexOf('--when-ci-commit-message') !== -1) {
let msg =
process.env.TRAVIS_COMMIT_MESSAGE ||
process.env.APPVEYOR_REPO_COMMIT_MESSAGE
if (!msg)
throw new Error(`Unable to guess the commit message from CI env variables`)
if (process.env.APPVEYOR_REPO_COMMIT_MESSAGE_EXTENDED) {
msg = `${msg}\n${process.env.APPVEYOR_REPO_COMMIT_MESSAGE_EXTENDED}`
}
if (!/\[ci npm-clean\]/.test(msg)) return
}

removeSync(Paths.distDir)
removeSync(join(Paths.testsRootDir, '*', 'coverage'))
removeSync(join(Paths.testsRootDir, '*', 'debug.txt'))
removeSync(join(Paths.testsRootDir, '*', 'node_modules'))
removeSync(join(Paths.e2eSourceDir, '*', 'node_modules'))
removeSync(join(Paths.e2eTemplatesDir, '*', 'node_modules'))
removeSync(Paths.e2eWorkDir)
removeSync(Paths.e2eWotkDirLink)
7 changes: 7 additions & 0 deletions src/__helpers__/path.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { resolve, relative } from 'path'

export const ROOT = resolve(__dirname, '..', '..')

export function relativeToRoot(path: string) {
return relative(ROOT, path)
}
49 changes: 49 additions & 0 deletions src/__helpers__/source-maps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// WARNING: this file is shared between e2e and unit tests
import { RawSourceMap } from 'source-map'
import bufferFrom from 'buffer-from'
import { relative, isAbsolute, resolve } from 'path'
import stableStringify = require('fast-json-stable-stringify')
import { realpathSync } from 'fs'

// source-map module doesn't provide a sync method to extract the source-maps
export function extractSourceMaps(source: string): RawSourceMap | undefined {
const [, comment]: [any, string | undefined] =
(source.match(
/[\n^]\/\/#\s*sourceMappingURL=data:application\/json;(?:charset=utf-8;)?base64,(\S+)\s*$/,
) as any) || []
if (!comment) return

return base64ToSourceMaps(comment)
}

export function base64ToSourceMaps(base64: string): RawSourceMap {
return JSON.parse(bufferFrom(base64, 'base64').toString('utf8'))
}

export function sourceMapsToBase64(sourceMaps: RawSourceMap): string {
return bufferFrom(stableStringify(sourceMaps)).toString('base64')
}

export function relativiseSourceRoot(
fromPath: string,
source: string,
prefix: string = '',
): string {
const from = realpathSync(fromPath)
const remap = (path: string): string =>
(isAbsolute(path)
? `${prefix}${relative(from, realpathSync(path))}`
: path
).replace(/\\/g, '/')

return source.replace(
/([\n^]\/\/#\s*sourceMappingURL=data:application\/json;(?:charset=utf-8;)?base64,)(\S+)(\s*)$/,
(_, before, base64, after) => {
const map = base64ToSourceMaps(base64)
if (map.sourceRoot) map.sourceRoot = remap(map.sourceRoot)
if (map.sources) map.sources = map.sources.map(remap)
if (map.file) map.file = remap(map.file)
return `${before}${sourceMapsToBase64(map)}${after}`
},
)
}
20 changes: 16 additions & 4 deletions src/lib/compiler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { TsJestGlobalOptions } from './types'
import { ConfigSet } from './config-set'
import * as fakers from '../__helpers__/fakers'
import { createCompiler } from './compiler'
import outdent from 'outdent'
import { extractSourceMaps } from '../__helpers__/source-maps'
import { relativeToRoot } from '../__helpers__/path'

// not really unit-testing here, but it's hard to mock all those values :-D

Expand Down Expand Up @@ -37,11 +38,22 @@ describe('typeCheck', () => {
),
).toThrowErrorMatchingInlineSnapshot(`
"⨯ Unable to compile TypeScript:
error TS5052: Option 'declarationDir' cannot be specified without specifying option 'declaration'.
error TS5053: Option 'declarationDir' cannot be specified with option 'outFile'.
error TS6082: Only 'amd' and 'system' modules are supported alongside --outFile.
[eval].ts(2,7): error TS2322: Type 'number' is not assignable to type 'string'.
"
`)
})
})

describe('source-maps', () => {
const compiler = makeCompiler()
it('should report diagnostics related to typings', () => {
const source = 'const f = (v: number) => v\nconst t: number = f(5)'
const compiled = compiler.compile(source, __filename)
const expectedFileName = relativeToRoot(__filename)
expect(extractSourceMaps(compiled)).toMatchObject({
file: expectedFileName,
sources: [expectedFileName],
sourcesContent: [source],
})
})
})
Loading

0 comments on commit 89a30c9

Please sign in to comment.