preprocessor sourcemaps: prettify code

sort devDependencies

rename to compile_options.sourcemap

file src/compiler/utils/string_with_map.ts
* indent with tabs
* run prettier
* remove extra whitespace
* add newline at end of file
* wrap long lines
* rephrase some comments
pull/5428/head
Milan Hauth 5 years ago
parent e223c35f1a
commit 43c5d5ecfc

@ -90,10 +90,10 @@
"rollup": "^1.27.14", "rollup": "^1.27.14",
"source-map": "^0.7.3", "source-map": "^0.7.3",
"source-map-support": "^0.5.13", "source-map-support": "^0.5.13",
"sourcemap-codec": "^1.4.8",
"tiny-glob": "^0.2.6", "tiny-glob": "^0.2.6",
"tslib": "^1.10.0", "tslib": "^1.10.0",
"typescript": "^3.5.3", "typescript": "^3.5.3"
"sourcemap-codec": "^1.4.8"
}, },
"nyc": { "nyc": {
"include": [ "include": [

@ -326,10 +326,10 @@ export default class Component {
this.source this.source
]; ];
if (compile_options.sourceMap) { if (compile_options.sourcemap) {
if (js.map) { if (js.map) {
const pre_remap_sources = js.map.sources; const pre_remap_sources = js.map.sources;
js.map = remapping([js.map, compile_options.sourceMap], () => null); js.map = remapping([js.map, compile_options.sourcemap], () => null);
// remapper can remove our source if it isn't used (no segments map back to it). It is still handy to have a source // remapper can remove our source if it isn't used (no segments map back to it). It is still handy to have a source
// so we add it back // so we add it back
if (js.map.sources && js.map.sources.length == 0) { if (js.map.sources && js.map.sources.length == 0) {
@ -351,7 +351,7 @@ export default class Component {
}); });
} }
if (css.map) { if (css.map) {
css.map = remapping([css.map, compile_options.sourceMap], () => null); css.map = remapping([css.map, compile_options.sourcemap], () => null);
} }
} }
} }

@ -12,7 +12,7 @@ const valid_options = [
'format', 'format',
'name', 'name',
'filename', 'filename',
'sourceMap', 'sourcemap',
'generate', 'generate',
'outputFilename', 'outputFilename',
'cssOutputFilename', 'cssOutputFilename',

@ -110,7 +110,7 @@ export interface CompileOptions {
filename?: string; filename?: string;
generate?: 'dom' | 'ssr' | false; generate?: 'dom' | 'ssr' | false;
sourceMap?: object | string; sourcemap?: object | string;
outputFilename?: string; outputFilename?: string;
cssOutputFilename?: string; cssOutputFilename?: string;
sveltePath?: string; sveltePath?: string;

@ -1,189 +1,235 @@
import { encode } from "sourcemap-codec"; import { encode } from "sourcemap-codec";
type MappingSegment = [ number ] | [ number, number, number, number ] | [ number, number, number, number, number ] type MappingSegment =
| [number]
| [number, number, number, number]
| [number, number, number, number, number];
type SourceMappings = { type SourceMappings = {
sources: string[]; sources: string[];
names: string[]; names: string[];
mappings: MappingSegment[][]; mappings: MappingSegment[][];
} };
type SourceLocation = { type SourceLocation = {
line: number; line: number;
column: number; column: number;
} };
function get_end_location(s: string): SourceLocation { function get_end_location(s: string): SourceLocation {
const parts = s.split('\n'); const parts = s.split("\n");
return { return {
line: parts.length - 1, line: parts.length - 1,
column: parts[parts.length - 1].length - 1 column: parts[parts.length - 1].length - 1,
}; };
} }
export function offset_source_location(
export function offset_source_location(offset: SourceLocation, map: SourceMappings): SourceMappings { offset: SourceLocation,
map: SourceMappings
const new_mappings = map.mappings.map(line => line.map(seg => { ): SourceMappings {
if (seg.length < 3) return seg; const new_mappings = map.mappings.map((line) =>
const new_seg = seg.slice() as MappingSegment; line.map((seg) => {
new_seg[2] = new_seg[2] + offset.line; if (seg.length < 3) return seg;
return new_seg; const new_seg = seg.slice() as MappingSegment;
})); new_seg[2] = new_seg[2] + offset.line;
return new_seg;
// first line has column altered })
if (new_mappings.length > 0) { );
new_mappings[0] = new_mappings[0].map(seg => {
if (seg.length < 4) return seg; // column changed in first line
const newSeg = seg.slice() as MappingSegment; if (new_mappings.length > 0) {
newSeg[3] = newSeg[3] + offset.column; new_mappings[0] = new_mappings[0].map((seg) => {
return newSeg; if (seg.length < 4) return seg;
}); const newSeg = seg.slice() as MappingSegment;
} newSeg[3] = newSeg[3] + offset.column;
return newSeg;
return { });
sources: map.sources, }
mappings: new_mappings
} as SourceMappings; return {
sources: map.sources,
mappings: new_mappings,
} as SourceMappings;
} }
function merge_tables<T>(
original: T[],
function merge_tables<T>( original: T[], extended: T[]): { table: T[]; new_idx: number[] } { extended: T[]
const table = original.slice(); ): { table: T[]; new_idx: number[] } {
const new_idx = []; const table = original.slice();
for (let j = 0; j < original.length; j++) { const new_idx = [];
const current = extended[j]; for (let j = 0; j < original.length; j++) {
const existing = table.indexOf(current); const current = extended[j];
if (existing < 0) { const existing = table.indexOf(current);
table.push(current); if (existing < 0) {
new_idx[j] = table.length - 1; table.push(current);
} else { new_idx[j] = table.length - 1;
new_idx[j] = existing; } else {
} new_idx[j] = existing;
} }
return { table, new_idx }; }
return { table, new_idx };
} }
export class GeneratedStringWithMap { export class GeneratedStringWithMap {
readonly generated: string; readonly generated: string;
readonly map: SourceMappings; readonly map: SourceMappings;
constructor(generated: string , map: SourceMappings) { constructor(generated: string, map: SourceMappings) {
this.generated = generated; this.generated = generated;
this.map = map; this.map = map;
} }
as_sourcemap() { as_sourcemap() {
return { return {
version: 3, version: 3,
sources: this.map.sources, sources: this.map.sources,
names: [], names: [],
mappings: encode(this.map.mappings as any) mappings: encode(this.map.mappings as any),
}; };
} }
concat(other: GeneratedStringWithMap): GeneratedStringWithMap { concat(other: GeneratedStringWithMap): GeneratedStringWithMap {
// if one is empty, return the other // if one is empty, return the other
if (this.generated.length == 0) return other; if (this.generated.length == 0) return other;
if (other.generated.length == 0) return this; if (other.generated.length == 0) return this;
//combine sources // combine sources
const { table: new_sources, new_idx: other_source_idx } = merge_tables(this.map.sources, other.map.sources); const {
const { table: new_names, new_idx: other_name_idx } = merge_tables(this.map.names, other.map.names); table: new_sources,
new_idx: other_source_idx
//update source and name references in segments } = merge_tables(
const other_mappings = other.map.mappings.map(line => line.map(seg => { this.map.sources,
//to reduce allocations, we only return a new segment if a value has changed other.map.sources
if ( );
(seg.length > 1 && other_source_idx[seg[1]] != seg[1]) // has source idx that has been updated const {
|| (seg.length == 5 && other_name_idx[seg[4]] != seg[4])) // has name idx that has been updated table: new_names,
{ new_idx: other_name_idx
const new_seg = seg.slice() as MappingSegment; } = merge_tables(
new_seg[1] = other_source_idx[seg[1]]; this.map.names,
if (seg.length == 5) { other.map.names
new_seg[4] = other_name_idx[seg[4]]; );
}
return new_seg; // update source refs and name refs in segments
} else { const other_mappings = other.map.mappings.map((line) =>
return seg; line.map((seg) => {
} // to reduce allocations,
})); // we only return a new segment if a value has changed
if (
//combine the mappings // new source idx
let new_mappings = this.map.mappings.slice(); (seg.length > 1 && other_source_idx[seg[1]] != seg[1]) ||
// new name idx
//shift the first line of the second mapping by the number of columns in the last line of the first (seg.length == 5 && other_name_idx[seg[4]] != seg[4])
const end = get_end_location(this.generated); ) {
const col_offset = end.column + 1; const new_seg = seg.slice() as MappingSegment;
const first_line = other_mappings.length == 0 ? [] : other_mappings[0].map(seg => { new_seg[1] = other_source_idx[seg[1]];
const new_seg = seg.slice() as MappingSegment; if (seg.length == 5) {
new_seg[0] = seg[0] + col_offset; new_seg[4] = other_name_idx[seg[4]];
return new_seg; }
}); return new_seg;
new_mappings[new_mappings.length - 1] = new_mappings[new_mappings.length - 1].concat(first_line); } else {
return seg;
//the rest don't need modification and can just be appended }
new_mappings = new_mappings.concat(other_mappings.slice(1) as MappingSegment[][]); })
);
return new GeneratedStringWithMap(this.generated + other.generated, {
sources: new_sources, // combine the mappings
names: new_names, let new_mappings = this.map.mappings.slice();
mappings: new_mappings
}); // shift the first line of the second mapping
} // by the number of columns in the last line of the first mapping
const end = get_end_location(this.generated);
const col_offset = end.column + 1;
static from_generated(generated: string, map?: SourceMappings): GeneratedStringWithMap { const first_line =
if (map) return new GeneratedStringWithMap(generated, map); other_mappings.length == 0
? []
const replacement_map: SourceMappings = { : other_mappings[0].map((seg) => {
names: [], const new_seg = seg.slice() as MappingSegment;
sources: [], new_seg[0] = seg[0] + col_offset;
mappings: [] return new_seg;
}; });
new_mappings[new_mappings.length - 1] = new_mappings[
if (generated.length == 0) return new GeneratedStringWithMap(generated, replacement_map); new_mappings.length - 1
].concat(first_line);
// we generate a mapping where the source was overwritten by the generated
const end = get_end_location(generated); // the rest don't need modification and can just be appended
for (let i = 0; i <= end.line; i++) { new_mappings = new_mappings.concat(
replacement_map.mappings.push([]); // unmapped line other_mappings.slice(1) as MappingSegment[][]
} );
return new GeneratedStringWithMap(generated, replacement_map); return new GeneratedStringWithMap(
} this.generated + other.generated, {
sources: new_sources,
names: new_names,
mappings: new_mappings,
static from_source(source_file: string, source: string, offset_in_source?: SourceLocation): GeneratedStringWithMap { });
const offset = offset_in_source || { line: 0, column: 0 }; }
const map: SourceMappings = {
names: [], static from_generated(
sources: [ source_file ], generated: string,
mappings: [] map?: SourceMappings
}; ): GeneratedStringWithMap {
if (map) return new GeneratedStringWithMap(generated, map);
if (source.length == 0) return new GeneratedStringWithMap(source, map);
const replacement_map: SourceMappings = {
// we create a high resolution identity map here, we know that it will eventually be names: [],
// merged with svelte's map, at which stage the resolution will decrease. sources: [],
const lines = source.split('\n'); mappings: [],
let pos = 0; };
const identity_map = lines.map((line, line_idx) => {
const segs = line.split(/([^\d\w\s]|\s+)/g).filter(x => x !== "").map(s => { if (generated.length == 0)
const seg: MappingSegment = [pos, 0, offset.line + line_idx, pos + (line_idx == 0 ? offset.column : 0)]; return new GeneratedStringWithMap(generated, replacement_map);
pos = pos + s.length;
return seg; // we generate a mapping
}); // where the source was overwritten by the generated
pos = 0; const end = get_end_location(generated);
return segs; for (let i = 0; i <= end.line; i++) {
}); replacement_map.mappings.push([]); // unmapped line
}
map.mappings = identity_map;
return new GeneratedStringWithMap(generated, replacement_map);
return new GeneratedStringWithMap(source, map); }
}
static from_source(
source_file: string,
source: string,
offset_in_source?: SourceLocation
): GeneratedStringWithMap {
const offset = offset_in_source || { line: 0, column: 0 };
const map: SourceMappings = {
names: [],
sources: [source_file],
mappings: [],
};
if (source.length == 0) return new GeneratedStringWithMap(source, map);
// we create a high resolution identity map here,
// we know that it will eventually be merged with svelte's map,
// at which stage the resolution will decrease.
const lines = source.split("\n");
let pos = 0;
const identity_map = lines.map((line, line_idx) => {
const segs = line
.split(/([^\d\w\s]|\s+)/g)
.filter((x) => x !== "")
.map((s) => {
const seg: MappingSegment = [
pos,
0,
offset.line + line_idx,
pos + (line_idx == 0 ? offset.column : 0),
];
pos = pos + s.length;
return seg;
});
pos = 0;
return segs;
});
map.mappings = identity_map;
return new GeneratedStringWithMap(source, map);
}
} }

@ -42,7 +42,7 @@ describe("sourcemaps", () => {
const { js, css } = svelte.compile(processed_input, { const { js, css } = svelte.compile(processed_input, {
filename, filename,
sourceMap: processed_map, sourcemap: processed_map,
outputFilename: `${outputFilename}.js`, outputFilename: `${outputFilename}.js`,
cssOutputFilename: `${outputFilename}.css` cssOutputFilename: `${outputFilename}.css`
}); });

Loading…
Cancel
Save