mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
Adds a built-in JSONL parser implemented in C++ using JavaScriptCore's
optimized JSON parser.
## API
### `Bun.JSONL.parse(input)`
Parse a complete JSONL string or `Uint8Array` and return an array of all
parsed values. Throws on invalid input.
```ts
const results = Bun.JSONL.parse('{"a":1}\n{"b":2}\n');
// [{ a: 1 }, { b: 2 }]
```
### `Bun.JSONL.parseChunk(input, start?, end?)`
Parse as many complete values as possible, returning `{ values, read,
done, error }`. Designed for streaming use cases where input arrives
incrementally.
```ts
const result = Bun.JSONL.parseChunk('{"id":1}\n{"id":2}\n{"id":3');
result.values; // [{ id: 1 }, { id: 2 }]
result.read; // 17
result.done; // false
result.error; // null
```
## Implementation Details
- C++ implementation in `BunObject.cpp` using JSC's `streamingJSONParse`
- ASCII fast path: zero-copy `StringView` for pure ASCII input
- Non-ASCII: uses `fromUTF8ReplacingInvalidSequences` with
`utf16_length_from_utf8` size check to prevent overflow
- UTF-8 BOM automatically skipped for `Uint8Array` input
- Pre-built `Structure` with fixed property offsets for fast result
object creation
- `Symbol.toStringTag = "JSONL"` on the namespace object
- `parseChunk` returns errors in `error` property instead of throwing,
preserving partial results
- Comprehensive boundary checks on start/end parameters
## Tests
234 tests covering:
- Complete and partial/streaming input scenarios
- Error handling and recovery
- UTF-8 multi-byte characters and BOM handling
- start/end boundary security (exhaustive combinations, clamping, OOB
prevention)
- 4 GB input rejection (both ASCII and non-ASCII paths)
- Edge cases (empty input, single values, whitespace, special numbers)
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
137 lines
4.2 KiB
CMake
137 lines
4.2 KiB
CMake
option(WEBKIT_VERSION "The version of WebKit to use")
|
|
option(WEBKIT_LOCAL "If a local version of WebKit should be used instead of downloading")
|
|
|
|
if(NOT WEBKIT_VERSION)
|
|
set(WEBKIT_VERSION daf95b4b4574799ff22c8c4effd0dc6e864968a5)
|
|
endif()
|
|
|
|
# Use preview build URL for Windows ARM64 until the fix is merged to main
|
|
set(WEBKIT_PREVIEW_PR 140)
|
|
|
|
string(SUBSTRING ${WEBKIT_VERSION} 0 16 WEBKIT_VERSION_PREFIX)
|
|
string(SUBSTRING ${WEBKIT_VERSION} 0 8 WEBKIT_VERSION_SHORT)
|
|
|
|
if(WEBKIT_LOCAL)
|
|
set(DEFAULT_WEBKIT_PATH ${VENDOR_PATH}/WebKit/WebKitBuild/${CMAKE_BUILD_TYPE})
|
|
else()
|
|
set(DEFAULT_WEBKIT_PATH ${CACHE_PATH}/webkit-${WEBKIT_VERSION_PREFIX})
|
|
endif()
|
|
|
|
option(WEBKIT_PATH "The path to the WebKit directory")
|
|
|
|
if(NOT WEBKIT_PATH)
|
|
set(WEBKIT_PATH ${DEFAULT_WEBKIT_PATH})
|
|
endif()
|
|
|
|
set(WEBKIT_INCLUDE_PATH ${WEBKIT_PATH}/include)
|
|
set(WEBKIT_LIB_PATH ${WEBKIT_PATH}/lib)
|
|
|
|
if(WEBKIT_LOCAL)
|
|
if(EXISTS ${WEBKIT_PATH}/cmakeconfig.h)
|
|
# You may need to run:
|
|
# make jsc-compile-debug jsc-copy-headers
|
|
include_directories(
|
|
${WEBKIT_PATH}
|
|
${WEBKIT_PATH}/JavaScriptCore/Headers
|
|
${WEBKIT_PATH}/JavaScriptCore/Headers/JavaScriptCore
|
|
${WEBKIT_PATH}/JavaScriptCore/PrivateHeaders
|
|
${WEBKIT_PATH}/bmalloc/Headers
|
|
${WEBKIT_PATH}/WTF/Headers
|
|
${WEBKIT_PATH}/JavaScriptCore/PrivateHeaders/JavaScriptCore
|
|
${WEBKIT_PATH}/JavaScriptCore/DerivedSources/inspector
|
|
)
|
|
|
|
# On Windows, add ICU include path from vcpkg
|
|
if(WIN32)
|
|
# Auto-detect vcpkg triplet
|
|
set(VCPKG_ARM64_PATH ${VENDOR_PATH}/WebKit/vcpkg_installed/arm64-windows-static)
|
|
set(VCPKG_X64_PATH ${VENDOR_PATH}/WebKit/vcpkg_installed/x64-windows-static)
|
|
if(EXISTS ${VCPKG_ARM64_PATH})
|
|
set(VCPKG_ICU_PATH ${VCPKG_ARM64_PATH})
|
|
else()
|
|
set(VCPKG_ICU_PATH ${VCPKG_X64_PATH})
|
|
endif()
|
|
if(EXISTS ${VCPKG_ICU_PATH}/include)
|
|
include_directories(${VCPKG_ICU_PATH}/include)
|
|
message(STATUS "Using ICU from vcpkg: ${VCPKG_ICU_PATH}/include")
|
|
endif()
|
|
endif()
|
|
endif()
|
|
|
|
# After this point, only prebuilt WebKit is supported
|
|
return()
|
|
endif()
|
|
|
|
if(WIN32)
|
|
set(WEBKIT_OS "windows")
|
|
elseif(APPLE)
|
|
set(WEBKIT_OS "macos")
|
|
elseif(UNIX)
|
|
set(WEBKIT_OS "linux")
|
|
else()
|
|
message(FATAL_ERROR "Unsupported operating system: ${CMAKE_SYSTEM_NAME}")
|
|
endif()
|
|
|
|
if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|ARM64|aarch64|AARCH64")
|
|
set(WEBKIT_ARCH "arm64")
|
|
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|x64|AMD64")
|
|
set(WEBKIT_ARCH "amd64")
|
|
else()
|
|
message(FATAL_ERROR "Unsupported architecture: ${CMAKE_SYSTEM_PROCESSOR}")
|
|
endif()
|
|
|
|
if(LINUX AND ABI STREQUAL "musl")
|
|
set(WEBKIT_SUFFIX "-musl")
|
|
endif()
|
|
|
|
if(DEBUG)
|
|
set(WEBKIT_SUFFIX "${WEBKIT_SUFFIX}-debug")
|
|
elseif(ENABLE_LTO)
|
|
set(WEBKIT_SUFFIX "${WEBKIT_SUFFIX}-lto")
|
|
else()
|
|
set(WEBKIT_SUFFIX "${WEBKIT_SUFFIX}")
|
|
endif()
|
|
|
|
if(ENABLE_ASAN)
|
|
# We cannot mix and match ASan Bun + non-ASan WebKit, or vice versa, because some WebKit classes
|
|
# change their layout according to whether ASan is used, for example:
|
|
# https://github.com/oven-sh/WebKit/blob/eda8b0fb4fb1aa23db9c2b00933df8b58bcdd289/Source/WTF/wtf/Vector.h#L682
|
|
set(WEBKIT_SUFFIX "${WEBKIT_SUFFIX}-asan")
|
|
endif()
|
|
|
|
setx(WEBKIT_NAME bun-webkit-${WEBKIT_OS}-${WEBKIT_ARCH}${WEBKIT_SUFFIX})
|
|
set(WEBKIT_FILENAME ${WEBKIT_NAME}.tar.gz)
|
|
|
|
if(WEBKIT_VERSION MATCHES "^autobuild-")
|
|
set(WEBKIT_TAG ${WEBKIT_VERSION})
|
|
else()
|
|
set(WEBKIT_TAG autobuild-${WEBKIT_VERSION})
|
|
endif()
|
|
|
|
setx(WEBKIT_DOWNLOAD_URL https://github.com/oven-sh/WebKit/releases/download/${WEBKIT_TAG}/${WEBKIT_FILENAME})
|
|
|
|
if(EXISTS ${WEBKIT_PATH}/package.json)
|
|
file(READ ${WEBKIT_PATH}/package.json WEBKIT_PACKAGE_JSON)
|
|
|
|
if(WEBKIT_PACKAGE_JSON MATCHES ${WEBKIT_VERSION})
|
|
return()
|
|
endif()
|
|
endif()
|
|
|
|
file(
|
|
DOWNLOAD ${WEBKIT_DOWNLOAD_URL} ${CACHE_PATH}/${WEBKIT_FILENAME} SHOW_PROGRESS
|
|
STATUS WEBKIT_DOWNLOAD_STATUS
|
|
)
|
|
if(NOT "${WEBKIT_DOWNLOAD_STATUS}" MATCHES "^0;")
|
|
message(FATAL_ERROR "Failed to download WebKit: ${WEBKIT_DOWNLOAD_STATUS}")
|
|
endif()
|
|
|
|
file(ARCHIVE_EXTRACT INPUT ${CACHE_PATH}/${WEBKIT_FILENAME} DESTINATION ${CACHE_PATH} TOUCH)
|
|
file(REMOVE ${CACHE_PATH}/${WEBKIT_FILENAME})
|
|
file(REMOVE_RECURSE ${WEBKIT_PATH})
|
|
file(RENAME ${CACHE_PATH}/bun-webkit ${WEBKIT_PATH})
|
|
|
|
if(APPLE)
|
|
file(REMOVE_RECURSE ${WEBKIT_INCLUDE_PATH}/unicode)
|
|
endif()
|