Skip to content

fix: absolute path for sources and add sources in dependendency #99

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package-lock.json

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

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
"dependencies": {
"data-urls": "^2.0.0",
"loader-utils": "^2.0.0",
"neo-async": "^2.6.1",
"schema-utils": "^2.6.6",
"source-map": "^0.6.0",
"whatwg-encoding": "^1.0.5"
Expand Down
117 changes: 57 additions & 60 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ import fs from 'fs';
import path from 'path';

import validateOptions from 'schema-utils';
import async from 'neo-async';
import parseDataURL from 'data-urls';
import { SourceMapConsumer } from 'source-map';
import { labelToName, decode } from 'whatwg-encoding';
import { getOptions, urlToRequest } from 'loader-utils';

import flattenSourceMap from './utils/flatten';

import schema from './options.json';
import { flattenSourceMap, normalize, MapAgregator } from './utils';

// Matches only the last occurrence of sourceMappingURL
const baseRegex =
Expand Down Expand Up @@ -121,70 +120,68 @@ export default function loader(input, inputMap) {
map = await flattenSourceMap(map);
}

if (map.sourcesContent && map.sourcesContent.length >= map.sources.length) {
callback(null, input.replace(match[0], ''), map);

return;
}

const sourcePrefix = map.sourceRoot ? `${map.sourceRoot}${path.sep}` : '';

// eslint-disable-next-line no-param-reassign
map.sources = map.sources.map((s) => sourcePrefix + s);

// eslint-disable-next-line no-param-reassign
delete map.sourceRoot;

const missingSources = map.sourcesContent
? map.sources.slice(map.sourcesContent.length)
: map.sources;

async.map(
missingSources,
// eslint-disable-next-line no-shadow
(source, callback) => {
resolve(context, urlToRequest(source, true), (resolveError, result) => {
if (resolveError) {
emitWarning(`Cannot find source file '${source}': ${resolveError}`);
const mapConsumer = await new SourceMapConsumer(map);

const resolvedSources = await Promise.all(
map.sources.map(async (source) => {
const fullPath = map.sourceRoot
? `${map.sourceRoot}/${source}`
: source;
const sourceData = new MapAgregator({
mapConsumer,
source,
fullPath,
emitWarning,
});

callback(null, null);
if (path.isAbsolute(fullPath)) {
return sourceData.content;
}

return new Promise((promiseResolve) => {
resolve(
context,
urlToRequest(fullPath, true),
(resolveError, result) => {
if (resolveError) {
emitWarning(
`Cannot find source file '${source}': ${resolveError}`
);

return promiseResolve(sourceData.placeholderContent);
}

sourceData.setFullPath(result);
return promiseResolve(sourceData.content);
}
);
});
})
);

return;
}
const resultMap = { ...map };
resultMap.sources = [];
resultMap.sourcesContent = [];

addDependency(result);
delete resultMap.sourceRoot;

fs.readFile(result, 'utf-8', (readFileError, content) => {
if (readFileError) {
emitWarning(
`Cannot open source file '${result}': ${readFileError}`
);
resolvedSources.forEach((res) => {
// eslint-disable-next-line no-param-reassign
resultMap.sources.push(normalize(res.source));
resultMap.sourcesContent.push(res.content);

callback(null, null);
if (res.source) {
addDependency(res.source);
}
});

return;
}
const sourcesContentIsEmpty =
resultMap.sourcesContent.filter((entry) => !!entry).length === 0;

callback(null, { source: result, content });
});
});
},
(err, info) => {
// eslint-disable-next-line no-param-reassign
map.sourcesContent = map.sourcesContent || [];

info.forEach((res) => {
if (res) {
// eslint-disable-next-line no-param-reassign
map.sources[map.sourcesContent.length] = res.source;
map.sourcesContent.push(res.content);
} else {
map.sourcesContent.push(null);
}
});
if (sourcesContentIsEmpty) {
delete resultMap.sourcesContent;
}

processMap(map, context, callback);
}
);
callback(null, input.replace(match[0], ''), resultMap);
}
}
90 changes: 90 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import fs from 'fs';

import sourceMap from 'source-map';

async function flattenSourceMap(map) {
const consumer = await new sourceMap.SourceMapConsumer(map);
let generatedMap;

if (map.file) {
generatedMap = new sourceMap.SourceMapGenerator({
file: map.file,
});
} else {
generatedMap = new sourceMap.SourceMapGenerator();
}

consumer.sources.forEach((sourceFile) => {
const sourceContent = consumer.sourceContentFor(sourceFile, true);
generatedMap.setSourceContent(sourceFile, sourceContent);
});

consumer.eachMapping((mapping) => {
const { source } = consumer.originalPositionFor({
line: mapping.generatedLine,
column: mapping.generatedColumn,
});

const mappings = {
source,
original: {
line: mapping.originalLine,
column: mapping.originalColumn,
},
generated: {
line: mapping.generatedLine,
column: mapping.generatedColumn,
},
};

if (source) {
generatedMap.addMapping(mappings);
}
});

return generatedMap.toJSON();
}

function normalize(path) {
return path.replace(/\\/g, '/');
}

function readFile(fullPath, charset, emitWarning) {
return new Promise((resolve) => {
fs.readFile(fullPath, charset, (readFileError, content) => {
if (readFileError) {
emitWarning(`Cannot open source file '${fullPath}': ${readFileError}`);

resolve({ source: fullPath, content: null });
}

resolve({ source: fullPath, content });
});
});
}

class MapAgregator {
constructor({ mapConsumer, source, fullPath, emitWarning }) {
this.fullPath = fullPath;
this.sourceContent = mapConsumer.sourceContentFor(source, true);
this.emitWarning = emitWarning;
}

setFullPath(path) {
this.fullPath = path;
}

get content() {
return this.sourceContent
? { source: this.fullPath, content: this.sourceContent }
: readFile(this.fullPath, 'utf-8', this.emitWarning);
}

get placeholderContent() {
return this.sourceContent
? { source: this.fullPath, content: this.sourceContent }
: { source: this.fullPath, content: null };
}
}

export { flattenSourceMap, normalize, MapAgregator };
46 changes: 0 additions & 46 deletions src/utils/flatten.js

This file was deleted.

30 changes: 21 additions & 9 deletions test/__snapshots__/loader.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,12 @@ Object {
}
`;

exports[`source-map-loader should process external SourceMaps: warnings 1`] = `Array []`;
exports[`source-map-loader should process external SourceMaps: warnings 1`] = `
Array [
"ModuleWarning: Module Warning (from \`replaced original path\`):
(Emitted value instead of an instance of Error) Cannot find source file 'external-source-map.txt': Error: Can't resolve './external-source-map.txt' in '/test/fixtures'",
]
`;

exports[`source-map-loader should process inlined SourceMaps with charset: css 1`] = `
"with SourceMap
Expand All @@ -64,7 +69,7 @@ Object {
"file": "charset-inline-source-map.js",
"mappings": "AAAA",
"sources": Array [
"charset-inline-source-map.txt",
"/test/fixtures/charset-inline-source-map.txt - (normalized for test)",
],
"sourcesContent": Array [
"with SourceMap",
Expand Down Expand Up @@ -96,7 +101,12 @@ Object {
}
`;

exports[`source-map-loader should process inlined SourceMaps: warnings 1`] = `Array []`;
exports[`source-map-loader should process inlined SourceMaps: warnings 1`] = `
Array [
"ModuleWarning: Module Warning (from \`replaced original path\`):
(Emitted value instead of an instance of Error) Cannot find source file 'inline-source-map.txt': Error: Can't resolve './inline-source-map.txt' in '/test/fixtures'",
]
`;

exports[`source-map-loader should skip invalid base64 SourceMap: css 1`] = `
"without SourceMap
Expand Down Expand Up @@ -133,7 +143,7 @@ Object {
exports[`source-map-loader should support absolute sourceRoot paths in sourcemaps: warnings 1`] = `Array []`;

exports[`source-map-loader should support indexed sourcemaps: css 1`] = `
"with SourceMap
"console.log('with SourceMap')
// Map taken from here
// https://github.com/mozilla/source-map/blob/master/test/util.js - indexedTestMapDifferentSourceRoots
"
Expand All @@ -147,7 +157,7 @@ Object {
"mappings": "CAAC,IAAI,IAAM,SAAU,GAClB,OAAO,IAAI;CCDb,IAAI,IAAM,SAAU,GAClB,OAAO",
"names": Array [],
"sources": Array [
"/the/root/nested1.js",
"/test/fixtures/indexed-sourcemap/nested1.js - (normalized for test)",
"/different/root/nested2.js",
],
"sourcesContent": Array [
Expand Down Expand Up @@ -210,7 +220,12 @@ Object {
}
`;

exports[`source-map-loader should use last SourceMap directive: warnings 1`] = `Array []`;
exports[`source-map-loader should use last SourceMap directive: warnings 1`] = `
Array [
"ModuleWarning: Module Warning (from \`replaced original path\`):
(Emitted value instead of an instance of Error) Cannot find source file 'inline-source-map.txt': Error: Can't resolve './inline-source-map.txt' in '/test/fixtures'",
]
`;

exports[`source-map-loader should warn on invalid SourceMap: css 1`] = `
"with SourceMap
Expand Down Expand Up @@ -271,9 +286,6 @@ Object {
"sources": Array [
"missing-source-map2.txt",
],
"sourcesContent": Array [
null,
],
"version": 3,
}
`;
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/charset-inline-source-map.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// Content
2 changes: 1 addition & 1 deletion test/fixtures/indexed-sourcemap/file.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
with SourceMap
console.log('with SourceMap')
//#sourceMappingURL=file.js.map
// Map taken from here
// https://github.com/mozilla/source-map/blob/master/test/util.js - indexedTestMapDifferentSourceRoots
3 changes: 1 addition & 2 deletions test/fixtures/indexed-sourcemap/file.js.map

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

Loading