mirror of https://github.com/sveltejs/svelte
parent
391455c58e
commit
90274b9739
@ -0,0 +1,88 @@
|
||||
import { decode as decode_mappings } from 'sourcemap-codec';
|
||||
import { Processed } from './types';
|
||||
|
||||
/**
|
||||
* Import decoded sourcemap from mozilla/source-map/SourceMapGenerator
|
||||
* Forked from source-map/lib/source-map-generator.js
|
||||
* from methods _serializeMappings and toJSON.
|
||||
* We cannot use source-map.d.ts types, because we access hidden properties.
|
||||
*/
|
||||
function decoded_sourcemap_from_generator(generator: any) {
|
||||
let previous_generated_line = 1;
|
||||
const converted_mappings = [[]];
|
||||
let result_line;
|
||||
let result_segment;
|
||||
let mapping;
|
||||
|
||||
const source_idx = generator._sources.toArray()
|
||||
.reduce((acc, val, idx) => (acc[val] = idx, acc), {});
|
||||
|
||||
const name_idx = generator._names.toArray()
|
||||
.reduce((acc, val, idx) => (acc[val] = idx, acc), {});
|
||||
|
||||
const mappings = generator._mappings.toArray();
|
||||
result_line = converted_mappings[0];
|
||||
|
||||
for (let i = 0, len = mappings.length; i < len; i++) {
|
||||
mapping = mappings[i];
|
||||
|
||||
if (mapping.generatedLine > previous_generated_line) {
|
||||
while (mapping.generatedLine > previous_generated_line) {
|
||||
converted_mappings.push([]);
|
||||
previous_generated_line++;
|
||||
}
|
||||
result_line = converted_mappings[mapping.generatedLine - 1]; // line is one-based
|
||||
} else if (i > 0) {
|
||||
const previous_mapping = mappings[i - 1];
|
||||
if (
|
||||
// sorted by selectivity
|
||||
mapping.generatedColumn === previous_mapping.generatedColumn &&
|
||||
mapping.originalColumn === previous_mapping.originalColumn &&
|
||||
mapping.name === previous_mapping.name &&
|
||||
mapping.generatedLine === previous_mapping.generatedLine &&
|
||||
mapping.originalLine === previous_mapping.originalLine &&
|
||||
mapping.source === previous_mapping.source
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
result_line.push([mapping.generatedColumn]);
|
||||
result_segment = result_line[result_line.length - 1];
|
||||
|
||||
if (mapping.source != null) {
|
||||
result_segment.push(...[
|
||||
source_idx[mapping.source],
|
||||
mapping.originalLine - 1, // line is one-based
|
||||
mapping.originalColumn
|
||||
]);
|
||||
if (mapping.name != null) {
|
||||
result_segment.push(name_idx[mapping.name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const map = {
|
||||
version: generator._version,
|
||||
sources: generator._sources.toArray(),
|
||||
names: generator._names.toArray(),
|
||||
mappings: converted_mappings
|
||||
};
|
||||
if (generator._file != null) {
|
||||
(map as any).file = generator._file;
|
||||
}
|
||||
// not needed: map.sourcesContent and map.sourceRoot
|
||||
return map;
|
||||
}
|
||||
|
||||
export function decode_map(processed: Processed) {
|
||||
let decoded_map = typeof processed.map === 'string' ? JSON.parse(processed.map) : processed.map;
|
||||
if (typeof(decoded_map.mappings) === 'string') {
|
||||
decoded_map.mappings = decode_mappings(decoded_map.mappings);
|
||||
}
|
||||
if ((decoded_map as any)._mappings && decoded_map.constructor.name === 'SourceMapGenerator') {
|
||||
// import decoded sourcemap from mozilla/source-map/SourceMapGenerator
|
||||
decoded_map = decoded_sourcemap_from_generator(decoded_map);
|
||||
}
|
||||
|
||||
return decoded_map;
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
export default function parse_tag_attributes(str: string) {
|
||||
const attrs = {};
|
||||
str.split(/\s+/).filter(Boolean).forEach(attr => {
|
||||
const p = attr.indexOf('=');
|
||||
if (p === -1) {
|
||||
attrs[attr] = true;
|
||||
} else {
|
||||
attrs[attr.slice(0, p)] = '\'"'.includes(attr[p + 1]) ?
|
||||
attr.slice(p + 2, -1) :
|
||||
attr.slice(p + 1);
|
||||
}
|
||||
});
|
||||
return attrs;
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
import { getLocator } from 'locate-character';
|
||||
import { StringWithSourcemap } from '../utils/string_with_sourcemap';
|
||||
|
||||
export interface Source {
|
||||
source: string;
|
||||
get_location: ReturnType<typeof getLocator>;
|
||||
filename: string;
|
||||
}
|
||||
|
||||
interface Replacement {
|
||||
offset: number;
|
||||
length: number;
|
||||
replacement: StringWithSourcemap;
|
||||
}
|
||||
|
||||
function calculate_replacements(
|
||||
re: RegExp,
|
||||
get_replacement: (...match: any[]) => Promise<StringWithSourcemap>,
|
||||
source: string
|
||||
) {
|
||||
const replacements: Array<Promise<Replacement>> = [];
|
||||
|
||||
source.replace(re, (...match) => {
|
||||
replacements.push(
|
||||
get_replacement(...match).then(
|
||||
replacement => {
|
||||
const matched_string = match[0];
|
||||
const offset = match[match.length-2];
|
||||
|
||||
return ({ offset, length: matched_string.length, replacement });
|
||||
}
|
||||
)
|
||||
);
|
||||
return '';
|
||||
});
|
||||
|
||||
return Promise.all(replacements);
|
||||
}
|
||||
|
||||
function perform_replacements(
|
||||
replacements: Replacement[],
|
||||
{ filename, source, get_location }: Source
|
||||
): StringWithSourcemap {
|
||||
const out = new StringWithSourcemap();
|
||||
let last_end = 0;
|
||||
|
||||
for (const { offset, length, replacement } of replacements) {
|
||||
const unchanged_prefix = StringWithSourcemap.from_source(
|
||||
filename, source.slice(last_end, offset), get_location(last_end));
|
||||
out.concat(unchanged_prefix).concat(replacement);
|
||||
last_end = offset + length;
|
||||
}
|
||||
|
||||
const unchanged_suffix = StringWithSourcemap.from_source(
|
||||
filename, source.slice(last_end), get_location(last_end));
|
||||
|
||||
return out.concat(unchanged_suffix);
|
||||
}
|
||||
|
||||
export async function replace_in_code(
|
||||
regex: RegExp,
|
||||
get_replacement: (...match: any[]) => Promise<StringWithSourcemap>,
|
||||
location: Source
|
||||
): Promise<StringWithSourcemap> {
|
||||
const replacements = await calculate_replacements(regex, get_replacement, location.source);
|
||||
|
||||
return perform_replacements(replacements, location);
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
export interface Processed {
|
||||
code: string;
|
||||
map?: string | object; // we are opaque with the type here to avoid dependency on the remapping module for our public types.
|
||||
dependencies?: string[];
|
||||
toString?: () => string;
|
||||
}
|
||||
|
||||
export interface PreprocessorGroup {
|
||||
markup?: (options: { content: string; filename: string }) => Processed | Promise<Processed>;
|
||||
style?: Preprocessor;
|
||||
script?: Preprocessor;
|
||||
}
|
||||
|
||||
export type Preprocessor = (options: {
|
||||
content: string;
|
||||
attributes: Record<string, string | boolean>;
|
||||
filename?: string;
|
||||
}) => Processed | Promise<Processed>;
|
Loading…
Reference in new issue