Track locations when parsing
This commit is contained in:
parent
f08f89d7ba
commit
e95e6e239f
4 changed files with 67 additions and 2 deletions
|
|
@ -21,6 +21,7 @@ export type Resolver = (id: string, base: string) => Promise<string | false | un
|
|||
|
||||
export interface CompileOptions {
|
||||
base: string
|
||||
from?: string
|
||||
onDependency: (path: string) => void
|
||||
shouldRewriteUrls?: boolean
|
||||
polyfills?: Polyfills
|
||||
|
|
@ -31,6 +32,7 @@ export interface CompileOptions {
|
|||
|
||||
function createCompileOptions({
|
||||
base,
|
||||
from,
|
||||
polyfills,
|
||||
onDependency,
|
||||
shouldRewriteUrls,
|
||||
|
|
@ -41,6 +43,7 @@ function createCompileOptions({
|
|||
return {
|
||||
base,
|
||||
polyfills,
|
||||
from,
|
||||
async loadModule(id: string, base: string) {
|
||||
return loadModule(id, base, onDependency, customJsResolver)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -10,3 +10,7 @@ const cssFile = readFileSync(currentFolder + './preflight.css', 'utf-8')
|
|||
bench('css-parser on preflight.css', () => {
|
||||
CSS.parse(cssFile)
|
||||
})
|
||||
|
||||
bench('CSS with sourcemaps', () => {
|
||||
CSS.parse(cssFile, { from: 'input.css' })
|
||||
})
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import {
|
|||
type Declaration,
|
||||
type Rule,
|
||||
} from './ast'
|
||||
import type { Source } from './source-maps/source'
|
||||
|
||||
const BACKSLASH = 0x5c
|
||||
const SLASH = 0x2f
|
||||
|
|
@ -31,7 +32,13 @@ const DASH = 0x2d
|
|||
const AT_SIGN = 0x40
|
||||
const EXCLAMATION_MARK = 0x21
|
||||
|
||||
export function parse(input: string) {
|
||||
export interface ParseOptions {
|
||||
from?: string
|
||||
}
|
||||
|
||||
export function parse(input: string, opts?: ParseOptions) {
|
||||
let source: Source | null = opts?.from ? { file: opts.from, code: input } : null
|
||||
|
||||
// Note: it is important that any transformations of the input string
|
||||
// *before* processing do NOT change the length of the string. This
|
||||
// would invalidate the mechanism used to track source locations.
|
||||
|
|
@ -48,6 +55,9 @@ export function parse(input: string) {
|
|||
let buffer = ''
|
||||
let closingBracketStack = ''
|
||||
|
||||
// The start of the first non-whitespace character in the buffer
|
||||
let bufferStart = 0
|
||||
|
||||
let peekChar
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
|
|
@ -72,6 +82,7 @@ export function parse(input: string) {
|
|||
// ```
|
||||
//
|
||||
if (currentChar === BACKSLASH) {
|
||||
if (buffer === '') bufferStart = i
|
||||
buffer += input.slice(i, i + 2)
|
||||
i += 1
|
||||
}
|
||||
|
|
@ -117,6 +128,11 @@ export function parse(input: string) {
|
|||
if (commentString.charCodeAt(2) === EXCLAMATION_MARK) {
|
||||
let node = comment(commentString.slice(2, -2))
|
||||
licenseComments.push(node)
|
||||
|
||||
if (source) {
|
||||
node.src = [source, start, i + 1]
|
||||
node.dst = [source, start, i + 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -313,6 +329,11 @@ export function parse(input: string) {
|
|||
let declaration = parseDeclaration(buffer, colonIdx)
|
||||
if (!declaration) throw new Error(`Invalid custom property, expected a value`)
|
||||
|
||||
if (source) {
|
||||
declaration.src = [source, start, i]
|
||||
declaration.dst = [source, start, i]
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
parent.nodes.push(declaration)
|
||||
} else {
|
||||
|
|
@ -333,6 +354,11 @@ export function parse(input: string) {
|
|||
else if (currentChar === SEMICOLON && buffer.charCodeAt(0) === AT_SIGN) {
|
||||
node = parseAtRule(buffer)
|
||||
|
||||
if (source) {
|
||||
node.src = [source, bufferStart, i]
|
||||
node.dst = [source, bufferStart, i]
|
||||
}
|
||||
|
||||
// At-rule is nested inside of a rule, attach it to the parent.
|
||||
if (parent) {
|
||||
parent.nodes.push(node)
|
||||
|
|
@ -369,6 +395,11 @@ export function parse(input: string) {
|
|||
throw new Error(`Invalid declaration: \`${buffer.trim()}\``)
|
||||
}
|
||||
|
||||
if (source) {
|
||||
declaration.src = [source, bufferStart, i]
|
||||
declaration.dst = [source, bufferStart, i]
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
parent.nodes.push(declaration)
|
||||
} else {
|
||||
|
|
@ -388,6 +419,12 @@ export function parse(input: string) {
|
|||
// At this point `buffer` should resemble a selector or an at-rule.
|
||||
node = rule(buffer.trim())
|
||||
|
||||
// Track the source location for source maps
|
||||
if (source) {
|
||||
node.src = [source, bufferStart, i]
|
||||
node.dst = [source, bufferStart, i]
|
||||
}
|
||||
|
||||
// Attach the rule to the parent in case it's nested.
|
||||
if (parent) {
|
||||
parent.nodes.push(node)
|
||||
|
|
@ -434,6 +471,12 @@ export function parse(input: string) {
|
|||
if (buffer.charCodeAt(0) === AT_SIGN) {
|
||||
node = parseAtRule(buffer)
|
||||
|
||||
// Track the source location for source maps
|
||||
if (source) {
|
||||
node.src = [source, bufferStart, i]
|
||||
node.dst = [source, bufferStart, i]
|
||||
}
|
||||
|
||||
// At-rule is nested inside of a rule, attach it to the parent.
|
||||
if (parent) {
|
||||
parent.nodes.push(node)
|
||||
|
|
@ -470,6 +513,11 @@ export function parse(input: string) {
|
|||
let node = parseDeclaration(buffer, colonIdx)
|
||||
if (!node) throw new Error(`Invalid declaration: \`${buffer.trim()}\``)
|
||||
|
||||
if (source) {
|
||||
node.src = [source, bufferStart, i]
|
||||
node.dst = [source, bufferStart, i]
|
||||
}
|
||||
|
||||
parent.nodes.push(node)
|
||||
}
|
||||
}
|
||||
|
|
@ -519,6 +567,8 @@ export function parse(input: string) {
|
|||
continue
|
||||
}
|
||||
|
||||
if (buffer === '') bufferStart = i
|
||||
|
||||
buffer += String.fromCharCode(currentChar)
|
||||
}
|
||||
}
|
||||
|
|
@ -529,6 +579,12 @@ export function parse(input: string) {
|
|||
if (buffer.charCodeAt(0) === AT_SIGN) {
|
||||
let node = parseAtRule(buffer)
|
||||
|
||||
// Track the source location for source maps
|
||||
if (source) {
|
||||
node.src = [source, bufferStart, input.length]
|
||||
node.dst = [source, bufferStart, input.length]
|
||||
}
|
||||
|
||||
ast.push(node)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ export const enum Polyfills {
|
|||
|
||||
type CompileOptions = {
|
||||
base?: string
|
||||
from?: string
|
||||
polyfills?: Polyfills
|
||||
loadModule?: (
|
||||
id: string,
|
||||
|
|
@ -136,6 +137,7 @@ async function parseCss(
|
|||
ast: AstNode[],
|
||||
{
|
||||
base = '',
|
||||
from,
|
||||
loadModule = throwOnLoadModule,
|
||||
loadStylesheet = throwOnLoadStylesheet,
|
||||
}: CompileOptions = {},
|
||||
|
|
@ -786,7 +788,7 @@ export async function compile(
|
|||
features: Features
|
||||
build(candidates: string[]): string
|
||||
}> {
|
||||
let ast = CSS.parse(css)
|
||||
let ast = CSS.parse(css, { from: opts.from })
|
||||
let api = await compileAst(ast, opts)
|
||||
let compiledAst = ast
|
||||
let compiledCss = css
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue