mirror of https://github.com/sveltejs/svelte
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 commentspull/5428/head
parent
e223c35f1a
commit
43c5d5ecfc
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in new issue