|
|
|
|
|
import { encode } from '@jridgewell/sourcemap-codec'; |
|
|
import { Context, dedent, indent, margin, newline, space } from './context.js'; |
|
|
|
|
|
|
|
|
let btoa = () => { |
|
|
throw new Error('Unsupported environment: `window.btoa` or `Buffer` should be supported.'); |
|
|
}; |
|
|
|
|
|
if (typeof window !== 'undefined' && typeof window.btoa === 'function') { |
|
|
btoa = (str) => window.btoa(unescape(encodeURIComponent(str))); |
|
|
} else if (typeof Buffer === 'function') { |
|
|
btoa = (str) => Buffer.from(str, 'utf-8').toString('base64'); |
|
|
} |
|
|
|
|
|
class SourceMap { |
|
|
version = 3; |
|
|
|
|
|
|
|
|
names = []; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(mappings, opts) { |
|
|
this.sources = [opts.sourceMapSource || null]; |
|
|
this.sourcesContent = [opts.sourceMapContent || null]; |
|
|
this.mappings = opts.sourceMapEncodeMappings === false ? mappings : encode(mappings); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
toString() { |
|
|
return JSON.stringify(this); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
toUrl() { |
|
|
return 'data:application/json;charset=utf-8;base64,' + btoa(this.toString()); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function print(node, visitors, opts = {}) { |
|
|
|
|
|
const commands = []; |
|
|
|
|
|
|
|
|
const context = new Context(visitors, commands); |
|
|
|
|
|
context.visit(node); |
|
|
|
|
|
|
|
|
|
|
|
let code = ''; |
|
|
let current_column = 0; |
|
|
|
|
|
|
|
|
let mappings = []; |
|
|
|
|
|
|
|
|
let current_line = []; |
|
|
|
|
|
|
|
|
function append(str) { |
|
|
code += str; |
|
|
|
|
|
for (let i = 0; i < str.length; i += 1) { |
|
|
if (str[i] === '\n') { |
|
|
mappings.push(current_line); |
|
|
current_line = []; |
|
|
current_column = 0; |
|
|
} else { |
|
|
current_column += 1; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
let current_newline = '\n'; |
|
|
const indent_str = opts.indent ?? '\t'; |
|
|
|
|
|
let needs_newline = false; |
|
|
let needs_margin = false; |
|
|
let needs_space = false; |
|
|
|
|
|
|
|
|
function run(command) { |
|
|
if (Array.isArray(command)) { |
|
|
for (let i = 0; i < command.length; i += 1) { |
|
|
run(command[i]); |
|
|
} |
|
|
return; |
|
|
} |
|
|
|
|
|
if (typeof command === 'number') { |
|
|
if (command === newline) { |
|
|
needs_newline = true; |
|
|
} else if (command === margin) { |
|
|
needs_margin = true; |
|
|
} else if (command === space) { |
|
|
needs_space = true; |
|
|
} else if (command === indent) { |
|
|
current_newline += indent_str; |
|
|
} else if (command === dedent) { |
|
|
current_newline = current_newline.slice(0, -indent_str.length); |
|
|
} |
|
|
|
|
|
return; |
|
|
} |
|
|
|
|
|
if (needs_newline) { |
|
|
append(needs_margin ? '\n' + current_newline : current_newline); |
|
|
} else if (needs_space) { |
|
|
append(' '); |
|
|
} |
|
|
|
|
|
needs_margin = needs_newline = needs_space = false; |
|
|
|
|
|
if (typeof command === 'string') { |
|
|
append(command); |
|
|
return; |
|
|
} |
|
|
|
|
|
if (command.type === 'Location') { |
|
|
current_line.push([ |
|
|
current_column, |
|
|
0, |
|
|
command.line - 1, |
|
|
command.column |
|
|
]); |
|
|
} |
|
|
} |
|
|
|
|
|
for (let i = 0; i < commands.length; i += 1) { |
|
|
run(commands[i]); |
|
|
} |
|
|
|
|
|
mappings.push(current_line); |
|
|
|
|
|
|
|
|
let map; |
|
|
|
|
|
return { |
|
|
code, |
|
|
|
|
|
get map() { |
|
|
return (map ??= new SourceMap(mappings, opts)); |
|
|
} |
|
|
}; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export { Context }; |
|
|
|