Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/esbuild/esbuild.github.io i…
Browse files Browse the repository at this point in the history
…nto sync-e8aefb01
  • Loading branch information
docschina-bot committed Jun 17, 2024
2 parents d1af358 + e8aefb0 commit f62a41d
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 16 deletions.
2 changes: 1 addition & 1 deletion src/content/content-types.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1762,7 +1762,7 @@ body:
- p: 'Loader: `empty`'

- p: >
This loader tells tells esbuild to pretend that a file is empty. It can be
This loader tells esbuild to pretend that a file is empty. It can be
a helpful way to remove content from your bundle in certain situations.
For example, you can configure `.css` files to load with `empty` to prevent
esbuild from bundling CSS files that are imported into JavaScript files:
Expand Down
17 changes: 15 additions & 2 deletions src/try/ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ async function reloadWorker(version: Version): Promise<Worker> {
}

export function sendIPC(message: IPCRequest): Promise<IPCResponse> {
function activateTask(worker: Worker, task: Task): void {
const activateTask = (worker: Worker, task: Task): void => {
if (activeTask) {
if (pendingTask) pendingTask.abort_()
pendingTask = task
Expand All @@ -183,9 +183,22 @@ export function sendIPC(message: IPCRequest): Promise<IPCResponse> {

return new Promise((resolve, reject) => {
workerPromise.then(worker => activateTask(worker, {
message_: message,
message_: serializeFunctions(message),
resolve_: resolve,
abort_: () => reject(new Error('Task aborted')),
}), reject)
})
}

// Hack: Serialize "Function" objects as "EvalError" objects instead
const serializeFunctions = (value: any): any => {
if (typeof value === 'function') {
const text = value + ''
return new EvalError('function ' + value.name + text.slice(text.indexOf('(')))
}
if (typeof value === 'object' && value) {
if (Array.isArray(value)) return value.map(serializeFunctions)
else return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, serializeFunctions(v)]))
}
return value
}
59 changes: 48 additions & 11 deletions src/try/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,31 @@ import { Mode } from './mode'
import { RichError } from './output'

const enum Kind {
// These must be in the order "-,:[]{}+"
// These must be in the order "-,:[]{}()+"
Minus,
Comma,
Colon,
OpenBracket,
CloseBracket,
OpenBrace,
CloseBrace,
OpenParen,
CloseParen,
Plus,

// The order doesn't matter for these
Identifier,
Function,
Literal,
String,
}

const enum Flags {
None = 0,
KeywordsAreIdentifiers = 1 << 0,
ExpectEndOfFile = 1 << 1,
}

interface Token {
line_: number
column_: number
Expand Down Expand Up @@ -390,7 +399,7 @@ function parseOptionsAsLooseJSON(input: string): Record<string, any> {
token.line_, token.column_ + token.text_.length, 0, '', 0, 0, 0, expected)
}

const nextToken = (expectEndOfFile = false): void => {
const nextToken = (flags = Flags.None): void => {
while (i < n) {
const tokenLine = line
const tokenColumn = i - lineStart
Expand Down Expand Up @@ -472,12 +481,12 @@ function parseOptionsAsLooseJSON(input: string): Record<string, any> {
}

// End of file
if (expectEndOfFile) {
if (flags & Flags.ExpectEndOfFile) {
throwRichError(input, `Expected end of file after ${where}`, line, i - lineStart, 0)
}

// Punctuation
const index = '-,:[]{}+'.indexOf(c)
const index = '-,:[]{}()+'.indexOf(c)
if (index >= 0) {
i++
token = { line_: tokenLine, column_: tokenColumn, kind_: index as Kind, text_: c, value_: c }
Expand Down Expand Up @@ -510,12 +519,14 @@ function parseOptionsAsLooseJSON(input: string): Record<string, any> {
const text = input.slice(start, i)
let kind = Kind.Literal
let value: any = text
if (text === 'null') value = null
if (flags & Flags.KeywordsAreIdentifiers) kind = Kind.Identifier
else if (text === 'null') value = null
else if (text === 'true') value = true
else if (text === 'false') value = false
else if (text === 'undefined') value = undefined
else if (text === 'Infinity') value = Infinity
else if (text === 'NaN') value = NaN
else if (text === 'function') kind = Kind.Function
else kind = Kind.Identifier
token = { line_: tokenLine, column_: tokenColumn, kind_: kind, text_: text, value_: value }
return
Expand Down Expand Up @@ -549,17 +560,36 @@ function parseOptionsAsLooseJSON(input: string): Record<string, any> {
throwRichError(input, `Unexpected ${JSON.stringify(c)} in ${where}`, line, i - lineStart, 1)
}

if (!expectEndOfFile) {
if (!(flags & Flags.ExpectEndOfFile)) {
throwRichError(input, `Unexpected end of file in ${where}`, line, i - lineStart, 0)
}
}

// Hack: Parse function literals by repeatedly using the browser's parser after each '}' character
const scanForFunctionLiteral = (name: string, from: number): Function => {
let closeBrace = /\}/g
let error = ''
closeBrace.lastIndex = from

for (let match: RegExpExecArray | null; match = closeBrace.exec(input);) {
try {
const code = new Function('return {' + name + input.slice(from, match.index + 1) + '}.' + name)
i = match.index + 1
return code()
} catch (err) {
error = ': ' + err.message
}
}

throwRichError(input, 'Invalid function literal' + error, token.line_, token.column_, token.text_.length)
}

const parseExpression = (): any => {
if (token.kind_ as number === Kind.OpenBrace) {
const object: Record<string, any> = Object.create(null)
const originals: Record<string, Token> = Object.create(null)
while (true) {
nextToken()
nextToken(Flags.KeywordsAreIdentifiers)
if (token.kind_ === Kind.CloseBrace) break
if (token.kind_ !== Kind.String && token.kind_ !== Kind.Identifier) throwUnexpectedToken()
const original = originals[token.value_]
Expand All @@ -568,10 +598,17 @@ function parseOptionsAsLooseJSON(input: string): Record<string, any> {
`The original key ${JSON.stringify(token.value_)} is here:`, original.line_, original.column_, original.text_.length)
}
const key = token
const endOfKey = i
let value: any
nextToken()
if (token.kind_ !== Kind.Colon) throwExpectedAfter(key, ':', 'property ' + JSON.stringify(key.value_))
nextToken()
object[key.value_] = parseExpression()
if (token.kind_ === Kind.OpenParen) value = scanForFunctionLiteral(key.value_, endOfKey)
else {
if (token.kind_ !== Kind.Colon) throwExpectedAfter(key, ':', 'property ' + JSON.stringify(key.value_))
nextToken()
if (token.kind_ === Kind.Function) value = scanForFunctionLiteral(key.value_, endOfKey)
else value = parseExpression()
}
object[key.value_] = value
originals[key.value_] = key
const beforeComma = token
nextToken()
Expand Down Expand Up @@ -617,7 +654,7 @@ function parseOptionsAsLooseJSON(input: string): Record<string, any> {

nextToken()
const root = parseExpression()
nextToken(true)
nextToken(Flags.ExpectEndOfFile)
return root
}

Expand Down
14 changes: 12 additions & 2 deletions src/try/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,16 @@ const formatMessages = (api: API, messages: Message[], options: FormatMessagesOp
}))
}

// Hack: Deserialize "EvalError" objects as "Function" objects instead
const deserializeFunctions = (value: any): any => {
if (typeof value === 'object' && value) {
if (value instanceof EvalError) return new Function('return ' + value.message)()
else if (Array.isArray(value)) return value.map(deserializeFunctions)
else return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, deserializeFunctions(v)]))
}
return value
}

onmessage = e => {
setup(e.data).then(api => {
onmessage = e => {
Expand Down Expand Up @@ -167,7 +177,7 @@ onmessage = e => {
}
}

const request: IPCRequest = e.data
const request: IPCRequest = deserializeFunctions(e.data)
const respond: (response: IPCResponse) => void = postMessage
let color = true

Expand Down Expand Up @@ -197,7 +207,7 @@ onmessage = e => {
api.build(request.options_).then(
({ warnings, outputFiles, metafile, mangleCache }) =>
finish(warnings, (stderr: string) => respond({
outputFiles_: outputFiles.map(({ path, text }) => ({ path, text })),
outputFiles_: outputFiles,
metafile_: metafile,
mangleCache_: mangleCache,
stderr_: stderr,
Expand Down

0 comments on commit f62a41d

Please sign in to comment.