Webpack and jest now have line source-map support, but coluns are still lacking
This commit is contained in:
Родитель
3c9c005e80
Коммит
2443014f49
|
@ -14,6 +14,9 @@
|
|||
"types": "monorepo-scripts types",
|
||||
"just": "monorepo-scripts"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map-js": "^1.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ts-jest": "*"
|
||||
},
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
describe("a jest test", () => {
|
||||
it("does nothing really", () => {
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
|
@ -3,7 +3,7 @@ function graphql(..._args: any[]) {
|
|||
}
|
||||
|
||||
describe("a jest test", () => {
|
||||
it("works", () => {
|
||||
it("succeeds", () => {
|
||||
expect(
|
||||
graphql`
|
||||
fragment SomeComponent_query on Query {
|
||||
|
@ -12,4 +12,14 @@ describe("a jest test", () => {
|
|||
`,
|
||||
).toEqual("hello world");
|
||||
});
|
||||
|
||||
it("fails", () => {
|
||||
expect(
|
||||
graphql`
|
||||
fragment SomeComponent_query on Query {
|
||||
helloWorld
|
||||
}
|
||||
`,
|
||||
).toEqual("bye world");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
|
||||
import { graphql } from "@nova/react";
|
||||
const doc = graphql\`query SomeComponentQuery($id: ID!) { helloWorld }\`;
|
||||
const doc = graphql`
|
||||
query SomeComponentQuery($id: ID!) {
|
||||
helloWorld
|
||||
}
|
||||
`;
|
||||
console.log()
|
||||
|
|
@ -1 +1 @@
|
|||
{"version":3,"sources":["fixture.ts"],"names":[],"mappings":"AACQ,OAAO,EACL,OAAO,EACR,MAAM,aAAa,CAAC;AACrB,MAAM,GAAG,GAHL,AAGQ,OAAO,CAAA,mDAAmD,CAAC,CAHR;AAI/D,OAAO,CAAC,GAAG,EAAE,CAAA","file":"fixture.js","sourceRoot":"","sourcesContent":["import { graphql } from \"@nova/react\";\nconst doc = graphql `query SomeComponentQuery($id: ID!) { helloWorld }`;\nconsole.log();\n//# sourceMappingURL=fixture.js.map"]}
|
||||
{"version":3,"sources":["fixture.ts"],"names":[],"mappings":"AAAA;AACA;AACA,oBAAoB,AACpB,AACA,AACA,AACA,6DAAS;AACT;AACA","file":"fixture.ts.map","sourcesContent":["\n import { graphql } from \"@nova/react\";\n const doc = graphql`\n query SomeComponentQuery($id: ID!) {\n helloWorld\n }\n `;\n console.log()\n "]}
|
|
@ -1,4 +1,5 @@
|
|||
import { graphql } from "@nova/react";
|
||||
const doc = require("./__generated__/SomeComponentQuery.graphql").default;
|
||||
console.log();
|
||||
//# sourceMappingURL=fixture.js.map
|
||||
|
||||
import { graphql } from "@nova/react";
|
||||
const doc = require("./__generated__/SomeComponentQuery.graphql").default;
|
||||
console.log()
|
||||
|
|
@ -1,31 +1,65 @@
|
|||
import { runCLI } from "jest";
|
||||
import type { Config } from "@jest/types";
|
||||
import * as path from "path";
|
||||
import { SourceMapGenerator } from "source-map-js";
|
||||
|
||||
describe("jest loader", () => {
|
||||
it("works", async () => {
|
||||
let output = "";
|
||||
jest.spyOn(process.stderr, "write").mockImplementation((chunk) => {
|
||||
if (typeof chunk === "string") {
|
||||
output += chunk;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
expect(await runJestTest("succeeds")).not.toMatch("failed");
|
||||
});
|
||||
|
||||
const roots = [path.join(__dirname, "./fixtures")];
|
||||
await runCLI(
|
||||
{
|
||||
roots,
|
||||
testRegex: "a-jest-test\\.ts$",
|
||||
runInBand: true,
|
||||
useStderr: true,
|
||||
transform: JSON.stringify({
|
||||
"\\.ts$": path.join(__dirname, "../ts-jest.ts"),
|
||||
}),
|
||||
} as Config.Argv,
|
||||
roots,
|
||||
);
|
||||
xit("uses the source-map to point at the correct failing line and column", async () => {
|
||||
expect(await runJestTest("fails")).toMatch("a-jest-test.ts:23:7");
|
||||
});
|
||||
|
||||
expect(output).not.toMatch(/failed/i);
|
||||
it("uses the source-map to point at the correct failing line", async () => {
|
||||
expect(await runJestTest("fails")).toMatch("a-jest-test.ts:23:1");
|
||||
});
|
||||
|
||||
it("does not perform any extra source-map processing when there were no changes", async () => {
|
||||
const spy = jest.spyOn(SourceMapGenerator, "fromSourceMap");
|
||||
await runJestTest("does nothing");
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
async function runJestTest(testNamePattern: string) {
|
||||
let output = "";
|
||||
jest.spyOn(process.stderr, "write").mockImplementation((chunk) => {
|
||||
if (typeof chunk === "string") {
|
||||
output += chunk;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
const roots = [path.join(__dirname, "./fixtures")];
|
||||
await runCLI(
|
||||
{
|
||||
roots,
|
||||
testRegex:
|
||||
testNamePattern === "does nothing"
|
||||
? "a-jest-test-without-doc\\.ts$"
|
||||
: "a-jest-test\\.ts$",
|
||||
testNamePattern,
|
||||
runInBand: true,
|
||||
useStderr: true,
|
||||
cache: false,
|
||||
transform: JSON.stringify({
|
||||
"\\.ts$": [path.join(__dirname, "../ts-jest.ts"), {}],
|
||||
}),
|
||||
} as Config.Argv,
|
||||
roots,
|
||||
);
|
||||
|
||||
return cleanAnsi(output);
|
||||
}
|
||||
|
||||
// Taken from vscode-jest, which is MIT licensed:
|
||||
// https://github.com/jest-community/vscode-jest/pull/501/files#diff-ca5696b367d474e785317cb7a0d9853fef5729387ab8d0fab4c46268c03aae99R135-R137
|
||||
function cleanAnsi(str: string): string {
|
||||
return str.replace(
|
||||
// eslint-disable-next-line no-control-regex
|
||||
/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
|
||||
"",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import { RunLoaderResult, runLoaders } from "loader-runner";
|
||||
import { SourceMapConsumer } from "source-map";
|
||||
import { SourceMapConsumer, MappingItem } from "source-map-js";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import { Position } from "source-map-js";
|
||||
|
||||
function runLoader(
|
||||
source: string,
|
||||
|
@ -37,16 +40,36 @@ function runLoader(
|
|||
});
|
||||
}
|
||||
|
||||
function getPositionOffset(str: string, line: number, column: number): number {
|
||||
function getPositionOffset(str: string, position: Position): number {
|
||||
const lines = str.split("\n");
|
||||
let offset = 0;
|
||||
for (let i = 0; i < line - 1; i++) {
|
||||
for (let i = 0; i < position.line - 1; i++) {
|
||||
offset += lines[i].length + 1;
|
||||
}
|
||||
offset += column;
|
||||
offset += position.column;
|
||||
return offset;
|
||||
}
|
||||
|
||||
function getGeneratedCodeForOriginalRange(
|
||||
originalStart: Position,
|
||||
originalEnd: Position,
|
||||
sourceMap: SourceMapConsumer,
|
||||
transpiled: string,
|
||||
): string {
|
||||
const generatedStart = sourceMap.generatedPositionFor({
|
||||
...originalStart,
|
||||
source: "fixture.ts",
|
||||
});
|
||||
const generatedEnd = sourceMap.generatedPositionFor({
|
||||
...originalEnd,
|
||||
source: "fixture.ts",
|
||||
});
|
||||
return transpiled.slice(
|
||||
getPositionOffset(transpiled, generatedStart),
|
||||
getPositionOffset(transpiled, generatedEnd),
|
||||
);
|
||||
}
|
||||
|
||||
describe("webpackLoader", () => {
|
||||
it.todo("works with watch query documents");
|
||||
it.todo("has a dependency on the artefact file");
|
||||
|
@ -161,25 +184,16 @@ describe("webpackLoader", () => {
|
|||
const result = await runLoader(source);
|
||||
const transpiled = result.result![0]?.toString();
|
||||
const sourceMap = result.result![1];
|
||||
|
||||
const consumer = new SourceMapConsumer(sourceMap!.toString() as any);
|
||||
const [startPosition, endPosition] = consumer.allGeneratedPositionsFor({
|
||||
line: 2,
|
||||
column: undefined as any,
|
||||
source: "fixture.ts",
|
||||
});
|
||||
const startOffset = getPositionOffset(
|
||||
transpiled!,
|
||||
startPosition.line,
|
||||
startPosition.column,
|
||||
);
|
||||
const endOffset = getPositionOffset(
|
||||
transpiled!,
|
||||
endPosition.line,
|
||||
endPosition.column,
|
||||
);
|
||||
|
||||
expect(transpiled?.slice(startOffset, endOffset)).toMatchInlineSnapshot(
|
||||
expect(
|
||||
getGeneratedCodeForOriginalRange(
|
||||
{ line: 3, column: 20 },
|
||||
{ line: 3, column: 79 },
|
||||
consumer,
|
||||
transpiled!,
|
||||
),
|
||||
).toMatchInlineSnapshot(
|
||||
`"require("./__generated__/SomeComponentQuery.graphql").default"`,
|
||||
);
|
||||
});
|
||||
|
@ -198,35 +212,65 @@ describe("webpackLoader", () => {
|
|||
const result = await runLoader(source);
|
||||
const transpiled = result.result![0]?.toString();
|
||||
const sourceMap = result.result![1];
|
||||
|
||||
const consumer = new SourceMapConsumer(sourceMap!.toString() as any);
|
||||
const startPosition = consumer.generatedPositionFor({
|
||||
line: 3,
|
||||
column: 20,
|
||||
source: "fixture.ts",
|
||||
});
|
||||
const endPosition = consumer.generatedPositionFor({
|
||||
line: 7,
|
||||
column: 10,
|
||||
source: "fixture.ts",
|
||||
});
|
||||
const startOffset = getPositionOffset(
|
||||
transpiled!,
|
||||
startPosition.line,
|
||||
startPosition.column,
|
||||
);
|
||||
const endOffset = getPositionOffset(
|
||||
transpiled!,
|
||||
endPosition.line,
|
||||
endPosition.column,
|
||||
);
|
||||
|
||||
expect(transpiled?.slice(startOffset, endOffset)).toMatchInlineSnapshot(
|
||||
// fs.writeFileSync(__dirname + "/tmp/test.out", transpiled!);
|
||||
// fs.writeFileSync(__dirname + "/tmp/test.map", sourceMap!);
|
||||
|
||||
expect(
|
||||
getGeneratedCodeForOriginalRange(
|
||||
{ line: 3, column: 20 },
|
||||
{ line: 7, column: 9 },
|
||||
consumer,
|
||||
transpiled!,
|
||||
),
|
||||
).toMatchInlineSnapshot(
|
||||
`"require("./__generated__/SomeComponentQuery.graphql").default"`,
|
||||
);
|
||||
});
|
||||
|
||||
xit("emits source-map that expands on existing input map", async () => {
|
||||
xit("emits source-mapping for the character immediately after a tagged template", async () => {
|
||||
const source = `
|
||||
import { graphql } from "@nova/react";
|
||||
const doc = graphql\`
|
||||
query SomeComponentQuery($id: ID!) {
|
||||
helloWorld
|
||||
}
|
||||
\`;
|
||||
console.log()
|
||||
`;
|
||||
|
||||
const result = await runLoader(source);
|
||||
const transpiled = result.result![0]?.toString();
|
||||
const sourceMap = result.result![1];
|
||||
const consumer = new SourceMapConsumer(sourceMap!.toString() as any);
|
||||
|
||||
expect(
|
||||
consumer.generatedPositionFor({
|
||||
line: 7,
|
||||
column: 9,
|
||||
source: "fixture.ts",
|
||||
}),
|
||||
).toMatchObject({ line: 3, column: 81 });
|
||||
// TODO: This is why the assertion below it fails. The column comes back the same as in the above assertion.
|
||||
expect(
|
||||
consumer.generatedPositionFor({
|
||||
line: 7,
|
||||
column: 10,
|
||||
source: "fixture.ts",
|
||||
}),
|
||||
).toMatchObject({ line: 3, column: 82 });
|
||||
expect(
|
||||
getGeneratedCodeForOriginalRange(
|
||||
{ line: 7, column: 9 },
|
||||
{ line: 7, column: 10 },
|
||||
consumer,
|
||||
transpiled!,
|
||||
),
|
||||
).toMatchInlineSnapshot(`";"`);
|
||||
});
|
||||
|
||||
it("emits source-map that expands on existing input map", async () => {
|
||||
// The import over multiple lines is important here, as it will transpile to a single line
|
||||
// and the source-map should be able to map back to the original source with multiple lines.
|
||||
const source = `
|
||||
|
@ -240,44 +284,16 @@ describe("webpackLoader", () => {
|
|||
const result = await runLoader(source, { compileTS: true });
|
||||
const transpiled = result.result![0]?.toString();
|
||||
const sourceMap = result.result![1];
|
||||
// console.log(transpiled);
|
||||
console.log(sourceMap);
|
||||
|
||||
const consumer = new SourceMapConsumer(sourceMap!.toString() as any);
|
||||
// consumer.eachMapping((mapping) => {
|
||||
// console.log(mapping);
|
||||
// });
|
||||
consumer.computeColumnSpans();
|
||||
console.log(
|
||||
consumer.allGeneratedPositionsFor({
|
||||
line: 5,
|
||||
column: undefined as any,
|
||||
source: "fixture.ts",
|
||||
}),
|
||||
);
|
||||
const [startPosition, endPosition] = consumer.allGeneratedPositionsFor({
|
||||
line: 5,
|
||||
column: undefined as any,
|
||||
source: "fixture.ts",
|
||||
});
|
||||
const x = consumer.generatedPositionFor({
|
||||
line: 5,
|
||||
column: 20,
|
||||
source: "fixture.ts",
|
||||
});
|
||||
console.log(x);
|
||||
const startOffset = getPositionOffset(
|
||||
transpiled!,
|
||||
2, // startPosition.line,
|
||||
12, // startPosition.column,
|
||||
);
|
||||
const endOffset = getPositionOffset(
|
||||
transpiled!,
|
||||
2, // endPosition.line,
|
||||
73, // endPosition.column,
|
||||
);
|
||||
|
||||
expect(transpiled?.slice(startOffset, endOffset)).toMatchInlineSnapshot(
|
||||
expect(
|
||||
getGeneratedCodeForOriginalRange(
|
||||
{ line: 5, column: 20 },
|
||||
{ line: 5, column: 80 },
|
||||
consumer,
|
||||
transpiled!,
|
||||
),
|
||||
).toMatchInlineSnapshot(
|
||||
`"require("./__generated__/SomeComponentQuery.graphql").default"`,
|
||||
);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
const COMMENT =
|
||||
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,";
|
||||
|
||||
export function addInlineSourceMap(source: string, sourceMap: string) {
|
||||
return `${source}\n${COMMENT}${Buffer.from(sourceMap).toString("base64")}\n`;
|
||||
}
|
||||
|
||||
export function extractInlineSourceMap(
|
||||
source: string,
|
||||
): [code: string, map: string | undefined] {
|
||||
const [sourceWithoutSourceMap, encodedSourceMap] = source.split(COMMENT);
|
||||
if (encodedSourceMap && sourceWithoutSourceMap) {
|
||||
return [
|
||||
sourceWithoutSourceMap,
|
||||
Buffer.from(encodedSourceMap, "base64").toString("utf8"),
|
||||
];
|
||||
} else {
|
||||
return [sourceWithoutSourceMap, undefined];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import { SourceMapConsumer, SourceMapGenerator } from "source-map-js";
|
||||
|
||||
export function applySourceMap(
|
||||
sourcePath: string,
|
||||
sourceMap1: string,
|
||||
sourceMap2: string,
|
||||
): string {
|
||||
const smc1 = new SourceMapConsumer(JSON.parse(sourceMap1));
|
||||
const smc2 = new SourceMapConsumer(JSON.parse(sourceMap2!));
|
||||
const pipeline = SourceMapGenerator.fromSourceMap(smc2);
|
||||
pipeline.applySourceMap(smc1, sourcePath);
|
||||
return pipeline.toString();
|
||||
}
|
|
@ -1,4 +1,107 @@
|
|||
import { SourceMapGenerator } from "source-map";
|
||||
import { SourceMapGenerator } from "source-map-js";
|
||||
|
||||
export function transform(
|
||||
source: string,
|
||||
sourcePath: string,
|
||||
sourceMap: SourceMapGenerator | undefined,
|
||||
): string | undefined {
|
||||
let anyChanges = false;
|
||||
|
||||
if (sourceMap) {
|
||||
sourceMap.addMapping({
|
||||
original: { line: 1, column: 0 },
|
||||
generated: { line: 1, column: 0 },
|
||||
source: sourcePath,
|
||||
});
|
||||
}
|
||||
|
||||
// This represents a chunk of the source either before a graphql tag, inside
|
||||
// a graphql tag, or after a graphql tag.
|
||||
let lastChunkOffset = 0;
|
||||
// This represents the number of lines that have been removed from the
|
||||
// generated source due to the removal of graphql tags.
|
||||
let lineDelta = 0;
|
||||
|
||||
const result = source.replace(
|
||||
/graphql\s*`(?:[^`])*`/g,
|
||||
(taggedTemplateExpression, offset: number) => {
|
||||
anyChanges = true;
|
||||
|
||||
if (sourceMap) {
|
||||
addNewLineMappings(
|
||||
lastChunkOffset,
|
||||
offset,
|
||||
source,
|
||||
sourceMap,
|
||||
lineDelta,
|
||||
sourcePath,
|
||||
);
|
||||
}
|
||||
|
||||
lastChunkOffset = offset + taggedTemplateExpression.length;
|
||||
|
||||
const match = taggedTemplateExpression.match(
|
||||
/(query|mutation|subscription|fragment)\s+\b(.+?)\b/,
|
||||
);
|
||||
if (match && match[2]) {
|
||||
const generated = `require("./__generated__/${match[2]}.graphql").default`;
|
||||
|
||||
if (sourceMap) {
|
||||
const originalStart = offsetToLineColumn(source, offset);
|
||||
sourceMap.addMapping({
|
||||
original: originalStart,
|
||||
generated: {
|
||||
line: originalStart.line - lineDelta,
|
||||
column: originalStart.column,
|
||||
},
|
||||
source: sourcePath,
|
||||
});
|
||||
|
||||
const originalEndOffset = offset + taggedTemplateExpression.length;
|
||||
forEachNewLine(offset, originalEndOffset, source, (offset) => {
|
||||
const lineStart = offsetToLineColumn(source, offset);
|
||||
sourceMap.addMapping({
|
||||
original: lineStart,
|
||||
generated: {
|
||||
line: originalStart.line - lineDelta,
|
||||
column: originalStart.column,
|
||||
},
|
||||
source: sourcePath,
|
||||
});
|
||||
});
|
||||
|
||||
sourceMap.addMapping({
|
||||
original: offsetToLineColumn(source, originalEndOffset),
|
||||
generated: {
|
||||
line: originalStart.line - lineDelta,
|
||||
column: originalStart.column + generated.length,
|
||||
},
|
||||
source: sourcePath,
|
||||
});
|
||||
|
||||
lineDelta += taggedTemplateExpression.split("\n").length - 1;
|
||||
}
|
||||
|
||||
return generated;
|
||||
}
|
||||
|
||||
return taggedTemplateExpression;
|
||||
},
|
||||
);
|
||||
|
||||
if (sourceMap) {
|
||||
addNewLineMappings(
|
||||
lastChunkOffset,
|
||||
source.length,
|
||||
source,
|
||||
sourceMap,
|
||||
lineDelta,
|
||||
sourcePath,
|
||||
);
|
||||
}
|
||||
|
||||
return anyChanges ? result : undefined;
|
||||
}
|
||||
|
||||
function offsetToLineColumn(
|
||||
str: string,
|
||||
|
@ -17,43 +120,36 @@ function offsetToLineColumn(
|
|||
return { line, column };
|
||||
}
|
||||
|
||||
export function transform(
|
||||
function forEachNewLine(
|
||||
start: number,
|
||||
end: number,
|
||||
source: string,
|
||||
sourcePath: string,
|
||||
sourceMap: SourceMapGenerator | undefined,
|
||||
callback: (offset: number) => void,
|
||||
) {
|
||||
return source.replace(
|
||||
/graphql\s*`(?:[^`])*`/g,
|
||||
(taggedTemplateExpression, offset: number) => {
|
||||
const match = taggedTemplateExpression.match(
|
||||
/(query|mutation|subscription|fragment)\s+\b(.+?)\b/,
|
||||
);
|
||||
if (match && match[2]) {
|
||||
const generated = `require("./__generated__/${match[2]}.graphql").default`;
|
||||
|
||||
if (sourceMap) {
|
||||
const originalStart = offsetToLineColumn(source, offset);
|
||||
sourceMap.addMapping({
|
||||
original: originalStart,
|
||||
generated: originalStart,
|
||||
source: sourcePath,
|
||||
});
|
||||
sourceMap.addMapping({
|
||||
original: offsetToLineColumn(
|
||||
source,
|
||||
offset + taggedTemplateExpression.length,
|
||||
),
|
||||
generated: {
|
||||
line: originalStart.line,
|
||||
column: originalStart.column + generated.length,
|
||||
},
|
||||
source: sourcePath,
|
||||
});
|
||||
}
|
||||
|
||||
return generated;
|
||||
}
|
||||
return taggedTemplateExpression;
|
||||
},
|
||||
);
|
||||
for (let i = start; i < end; i++) {
|
||||
if (source[i] === "\n") {
|
||||
callback(i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addNewLineMappings(
|
||||
start: number,
|
||||
end: number,
|
||||
source: string,
|
||||
sourceMap: SourceMapGenerator,
|
||||
lineDelta: number,
|
||||
sourcePath: string,
|
||||
) {
|
||||
forEachNewLine(start, end, source, (offset) => {
|
||||
const lineStart = offsetToLineColumn(source, offset);
|
||||
sourceMap.addMapping({
|
||||
original: lineStart,
|
||||
generated: {
|
||||
line: lineStart.line - lineDelta,
|
||||
column: lineStart.column,
|
||||
},
|
||||
source: sourcePath,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,26 +1,57 @@
|
|||
import { transform } from "./transform";
|
||||
import tsLoader from "ts-jest";
|
||||
import { SourceMapGenerator } from "source-map-js";
|
||||
|
||||
import type { TransformerFactory, SyncTransformer } from "@jest/transform";
|
||||
import type { TsJestGlobalOptions } from "ts-jest";
|
||||
import { extractInlineSourceMap } from "./addInlineSourceMap";
|
||||
import { applySourceMap } from "./source-map-utils";
|
||||
|
||||
const transformerFactory: TransformerFactory<SyncTransformer<unknown>> = {
|
||||
createTransformer(config) {
|
||||
const tsLoaderInstance = tsLoader.createTransformer(
|
||||
config as TsJestGlobalOptions,
|
||||
);
|
||||
const generateSourceMap = true;
|
||||
return {
|
||||
...tsLoaderInstance,
|
||||
process(sourceText, sourcePath, options) {
|
||||
return tsLoaderInstance.process(
|
||||
transform(sourceText, sourcePath, undefined),
|
||||
const sourceMap = generateSourceMap
|
||||
? new SourceMapGenerator()
|
||||
: undefined;
|
||||
sourceMap?.setSourceContent(sourcePath, sourceText);
|
||||
const transformed = transform(sourceText, sourcePath, sourceMap);
|
||||
|
||||
let tsResult = tsLoaderInstance.process(
|
||||
transformed || sourceText,
|
||||
sourcePath,
|
||||
options,
|
||||
);
|
||||
|
||||
if (sourceMap && transformed) {
|
||||
const [tsResultCode, tsResultMap] = extractInlineSourceMap(
|
||||
tsResult.code,
|
||||
);
|
||||
if (tsResultMap === undefined) {
|
||||
throw new Error("Expected inline source-map");
|
||||
}
|
||||
// TODO: Determine why ts-jest insists on using inline source-maps
|
||||
// and/or if it's cheaper to inline the source-map again
|
||||
// ourselves rather than letting jest do the work.
|
||||
tsResult = {
|
||||
code: tsResultCode,
|
||||
map: applySourceMap(sourcePath, sourceMap.toString(), tsResultMap),
|
||||
};
|
||||
}
|
||||
|
||||
return tsResult;
|
||||
},
|
||||
processAsync(sourceText, sourcePath, options) {
|
||||
const sourceMapGenerator = new SourceMapGenerator();
|
||||
sourceMapGenerator.setSourceContent(sourcePath, sourceText);
|
||||
|
||||
return tsLoaderInstance.processAsync(
|
||||
transform(sourceText, sourcePath, undefined),
|
||||
transform(sourceText, sourcePath, sourceMapGenerator)!,
|
||||
sourcePath,
|
||||
options,
|
||||
);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import type { LoaderDefinitionFunction } from "webpack";
|
||||
import { SourceMapConsumer, SourceMapGenerator } from "source-map";
|
||||
import { SourceMapConsumer, SourceMapGenerator } from "source-map-js";
|
||||
import { transform } from "./transform";
|
||||
import { applySourceMap } from "./source-map-utils";
|
||||
|
||||
const webpackLoader: LoaderDefinitionFunction = function (
|
||||
source,
|
||||
|
@ -11,33 +12,31 @@ const webpackLoader: LoaderDefinitionFunction = function (
|
|||
|
||||
let sourceMap: SourceMapGenerator | undefined;
|
||||
if (this.sourceMap) {
|
||||
// sourceMap = inputSourceMap
|
||||
// ? SourceMapGenerator.fromSourceMap(
|
||||
// new SourceMapConsumer(JSON.parse(inputSourceMap as string)),
|
||||
// )
|
||||
// : new SourceMapGenerator({
|
||||
// file: this.resourcePath + ".map",
|
||||
// });
|
||||
sourceMap = new SourceMapGenerator({
|
||||
file: this.resourcePath + ".map",
|
||||
});
|
||||
sourceMap.setSourceContent(this.resourcePath, source);
|
||||
}
|
||||
|
||||
const result = transform(source, this.resourcePath, sourceMap);
|
||||
const transformed = transform(source, this.resourcePath, sourceMap);
|
||||
|
||||
if (sourceMap && inputSourceMap) {
|
||||
const compoundSourceMap = SourceMapGenerator.fromSourceMap(
|
||||
new SourceMapConsumer(JSON.parse(inputSourceMap as string)),
|
||||
if (transformed && sourceMap && inputSourceMap) {
|
||||
callback(
|
||||
null,
|
||||
transformed,
|
||||
applySourceMap(
|
||||
this.resourcePath,
|
||||
inputSourceMap as string,
|
||||
sourceMap.toString(),
|
||||
),
|
||||
);
|
||||
compoundSourceMap.applySourceMap(
|
||||
new SourceMapConsumer(JSON.parse(sourceMap.toString())),
|
||||
);
|
||||
|
||||
sourceMap = compoundSourceMap;
|
||||
} else if (transformed && sourceMap) {
|
||||
callback(null, transformed, sourceMap.toString());
|
||||
} else if (transformed) {
|
||||
callback(null, transformed);
|
||||
} else {
|
||||
callback(null, source);
|
||||
}
|
||||
|
||||
callback(null, result, sourceMap?.toString());
|
||||
};
|
||||
|
||||
export default webpackLoader;
|
||||
|
|
|
@ -11227,6 +11227,11 @@ sockjs@^0.3.21, sockjs@^0.3.24:
|
|||
uuid "^8.3.2"
|
||||
websocket-driver "^0.7.4"
|
||||
|
||||
source-map-js@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
|
||||
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
|
||||
|
||||
source-map-resolve@^0.5.0:
|
||||
version "0.5.3"
|
||||
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
|
||||
|
|
Загрузка…
Ссылка в новой задаче